代碼優化之減小重複代碼-實踐

背景

在APP中列表是一種比較常見的數據展現方式,當有數據時,就顯示數據;若是沒有數據,通常不會顯示一個空白頁面,而是在空白頁面上加一些提示信息,好比像下面這樣:atom

不一樣的APP會有不一樣的設計,但無論是什麼樣的設計,它在整個APP內部應該是一致的,要變也只是文字或圖片稍有不一樣。spa

現狀

由於咱們目前的項目還算比較龐大,因此這種列表無數據的狀況出現了20屢次,因此相似下面的代碼出現了就有20屢次。爲何說相似,由於是由不一樣的人寫的,邏輯也是差很少,但真的各不相同,有的封裝成一個方法,好比:setNoMessageView,有的直接寫在viewDidLoad裏面......設計

- (void)setNoMessageView
 {
     self.noInfoView = [[UIView alloc] initWithFrame:CGRectMake(0, 45, SCREEN_WIDTH, SCREEN_HEIGHT)];
     self.noInfoView.backgroundColor = [UIColor clearColor];
     [self.view addSubview:self.noInfoView];

     UIImageView *carImageView = [[UIImageView alloc] initWithFrame:CGRectMake((SCREEN_WIDTH-120)/2, 60, 120, 86)];
     [carImageView setImage:[UIImage imageNamed:@"no_message.png"]];
     [self.noInfoView addSubview:carImageView];

     UILabel *noInfoLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 160, SCREEN_WIDTH, 20)];
     noInfoLabel.textAlignment = NSTextAlignmentCenter;
     noInfoLabel.textColor = LCRGBColor(211, 211, 211);
     noInfoLabel.text = NSLocalizedString(@"Dear, no information", nil);
     noInfoLabel.backgroundColor = [UIColor clearColor];
     noInfoLabel.font = [LCFont systemFontOfSize:20];
     [self.noInfoView addSubview:noInfoLabel];
 }

先不考慮重複的問題,只是孤立的看上述代碼,它也有一些問題:code

  • self.noInfoView的frame應該視根據上下文得到的,而不是和屏幕大小綁定,並且yOffset是45也是不對的。
  • carImageView的frame是固定大小的,而圖片有可能變。

第一個解決辦法

由於建立noInfoView的代碼基本差很少,咱們能夠封裝出一個Util方法。orm

+ (UIView*)createNoMessageViewWithFrame:(CGRect)frame image:(UIImage*)image text:(NSString*)text
{
    UIView* noMessageView = [[UIView alloc] initWithFrame:frame];
    noMessageView.backgroundColor = [UIColor clearColor];

    UIImageView *carImageView = [[UIImageView alloc] initWithFrame:CGRectMake((frame.size.width-image.size.width)/2, 60, image.size.width, image.size.height)];
    [carImageView setImage:image];
    [noMessageView addSubview:carImageView];

    UILabel *noInfoLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 160, frame.size.width, 20)];
    noInfoLabel.textAlignment = NSTextAlignmentCenter;
    noInfoLabel.textColor = LCRGBColor(211, 211, 211);
    noInfoLabel.text = text;
    noInfoLabel.backgroundColor = [UIColor clearColor];
    noInfoLabel.font = [LCFont systemFontOfSize:20];
    [noMessageView addSubview:noInfoLabel];

    return noMessageView;
}

調用:blog

- (void)setNoMessageView
{
    CGRect rect = self.shopListView.frame;
    UIImage* image = [UIImage imageNamed:@"no_message.png"];
    NSString* text = NSLocalizedString(@"Dear, no information", nil);
    self.noInfoView = [HJUIUtil createNoMessageViewWithFrame:rect image:image text:text];
    [self.view addSubview:self.noInfoView];
}

這樣改看起來好多了,把共性封裝,把差別做爲接口留出。而後其餘地方本來要寫20行代碼,如今只要寫5行,並且多個地方調用的代碼不會有太大的出入,便於閱讀和理解。接口

第二個解決辦法

上面的辦法已經不錯了,不過除了寫5行代碼以外,還給ViewController增長了一個屬性:noInfoView。如今仔細想一下noInfoView出現的緣由,是由於TableView沒有內容顯示的時候,noInfoView才顯示出來,不然就隱藏。可見,這個noInfoView和TableView是緊密聯繫的,咱們能夠從UITableView的狀態得出noInfoView的狀態。那爲何不把它綁定到UITableView上呢?好,那就給UITableView增長一個屬性,叫作emptyView。圖片

給一個系統的類增長屬性不是那麼的簡單,可是隻要看過SVPullToRefresh的代碼,就知道怎麼作了。
首先,給UITableView增長一個Category。ci

@interface UITableView(EmptyView)

@property (nonatomic, strong, readonly) UIView *emptyView;

-(void)addEmptyViewWithImageName:(NSString*)imageName title:(NSString*)title;

@end
static char UITableViewEmptyView;

@implementation UITableView(EmptyView)

@dynamic emptyView;

- (UIView *)emptyView
{
    return objc_getAssociatedObject(self, &UITableViewEmptyView);
}

- (void)setEmptyView:(UIView *)emptyView
{
    [self willChangeValueForKey:@"HJEmptyView"];
    objc_setAssociatedObject(self, &UITableViewEmptyView,
                             emptyView,
                             OBJC_ASSOCIATION_ASSIGN);
    [self didChangeValueForKey:@"HJEmptyView"];
}


-(void)addEmptyViewWithImageName:(NSString*)imageName title:(NSString*)title
{
    if (!self.emptyView)
    {
        CGRect frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
        UIImage* image = [UIImage imageNamed:imageName];
        NSString* text = title;

        UIView* noMessageView = [[UIView alloc] initWithFrame:frame];
        noMessageView.backgroundColor = [UIColor clearColor];

        UIImageView *carImageView = [[UIImageView alloc] initWithFrame:CGRectMake((frame.size.width-image.size.width)/2, 60, image.size.width, image.size.height)];
        [carImageView setImage:image];
        [noMessageView addSubview:carImageView];

        UILabel *noInfoLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 160, frame.size.width, 20)];
        noInfoLabel.textAlignment = NSTextAlignmentCenter;
        noInfoLabel.textColor = LCRGBColor(211, 211, 211);
        noInfoLabel.text = text;
        noInfoLabel.backgroundColor = [UIColor clearColor];
        noInfoLabel.font = [LCFont systemFontOfSize:20];
        [noMessageView addSubview:noInfoLabel];

        [self addSubview:noMessageView];

        self.emptyView = noMessageView;
    }

}

@end

而後外部調用就很簡單了,沒有額外的屬性,並且一句話就搞定。get

[self.shopListView.shopListTableView addEmptyViewWithImageName:@"no_message.png" title:@"Dear, no information"];

而後在加載數據前進行斷定是否顯示emptyView

self.shopListView.shopListTableView.emptyView.hidden = ([self.dataArray count] != 0);
相關文章
相關標籤/搜索