美文网首页iOS
iOS开发之让控制器变得更轻量级

iOS开发之让控制器变得更轻量级

作者: Jamp_iOS | 来源:发表于2015-11-27 23:31 被阅读917次

    为何要轻量级

    通常,项目中有些 viewControllers 非常臃肿,把一些控制器不需要知道的代码和逻辑全都放在了控制器的文件中,小则好几百行大则上千,代码风格飘忽不定,前逻辑后数据处理,让擦屁股的人苦不堪言,"尼玛,这都是什么玩意儿!!!".今天我们来研究如何把这些代码搬到合适的位置,让你的 viewControllers 从此告别"脂肪",挺起双峰.

    如何变得轻量级

    1. 剥去 UITableViewDataSource 代理方法

    项目中很多地方会用到 tableView 来展示数据, 同样 viewController 会实现 UITableViewDataSource 的以下代理方法

    
    - (id)itemAtIndexPath:(NSIndexPath *)indexPath{
        return _items[indexPath.row];
    }
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
        return _items.count;
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
        
        FYBaseCell *cell = (FYBaseCell *)[tableView dequeueReusableCellWithIdentifier:_cellIdentifier];
        
        if (_cellType == kFYCellTypeDefault) {
            if (!cell) {
                cell = [[DemoCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:_cellIdentifier];
            }
        }
        
        id item = [self itemAtIndexPath:indexPath];
        [cell  configureCellContentWithItem:item];
        return cell;
    }
    

    这些 dataSource 方法可以不用在 viewControllers 中实现,因为 viewControllers 并不关心 cell 如何展示数据,所以我们可以抽象出一个 FYDataSource 类出来,实现 UITableViewDataSource 代理方法

    
    @interface FYDataSource()
    
    @property (nonatomic, copy)         NSString *cellIdentifier;
    @property (nonatomic, assign)       kFYCellType cellType;
    
    @end
    - (id)itemAtIndexPath:(NSIndexPath *)indexPath{
        return _items[indexPath.row];
    }
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
        return _items.count;
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
        
        FYBaseCell *cell = (FYBaseCell *)[tableView dequeueReusableCellWithIdentifier:_cellIdentifier];
        
        if (_cellType == kFYCellTypeDefault) {
            if (!cell) {
                cell = [[DemoCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:_cellIdentifier];
            }
        }
        
        id item = [self itemAtIndexPath:indexPath];
        [cell  configureCellContentWithItem:item];
        return cell;
    }
    
    

    我们再给这个抽象类添加一个实例方法,下面贴出 FYDataSource 这个类的头文件代码

    // FYDataSource.h 文件的代码
    
    typedef NS_ENUM(NSInteger, kFYCellType){
        kFYCellTypeDefault = 0,
    };
    
    @interface FYDataSource : NSObject <UITableViewDataSource>
    @property (nonatomic, strong)       NSArray *items;  //模型数组
    
    /**
     *  创建一个FYDataSource对象
     *
     *  @param items          模型数组
     *  @param cellIdentifier cell的缓存标识符
     *  @param cellType       cell类型
     *
     *  @return 实例好的FYDataSource对象
     */
    - (instancetype)initWithItems:(NSArray *)items cellIdentifier:(NSString *)cellIdentifier cellType:(kFYCellType)cellType;
    
    @end
    

    *这样就成功剥离了 UITableViewDataSource 的代理方法,并且多了 FYDataSource 这个工具类, �可以复用, 与此同时你可以实现其它 UITableViewDataSource 代理方法,比如: *

    tableView:commitEditingStyle:forRowAtIndexPath:
    

    同样的方法你也可以使用在 UICollectionViewDataSource 这个类上,赶紧给你的 viewControllers 瘦身吧!

    *2. 剥去 UITableViewDelegate 方法 *

    *同样 UITableViewDelegate 的代理方法在控制器中也占据这不少的篇幅,我们也可以给它剥离出来,这里我把代理方法在 FYDataSource 中,同时通过代理传出一些必要参数给控制器,代码如下: *

    //  .h 文件
    
    @protocol FYDataSourceDelegate <NSObject>
    
    @optional
    /**
     *  点击cell的代理方法,传出对应的item模型以及对应的tablview
     *
     *  @param item      对应的item
     *  @param tableView 对应的tablview
     */
    - (void)didSelectedCellWithItem:(id)item tableView:(UITableView *)tableView;
    
    - (CGFloat)heightForHeaderInSection:(NSInteger)section tableView:(UITableView *)tableView;
    - (UIView *)viewForHeaderInSection:(NSInteger)section tableView:(UITableView *)tableView;
    
    - (CGFloat)heightForFooterInSection:(NSInteger)section tableView:(UITableView *)tableView;
    - (UIView *)viewForFooterInSection:(NSInteger)section tableView:(UITableView *)tableView;
    
    - (NSArray<NSString *> *)sectionIndexTitlesForTableView:(UITableView *)tableView;
    
    @end
    
    // .m 文件中的实现
    #pragma mark
    #pragma mark - UITableViewDelegate
    
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
        
        id item = [self itemAtIndexPath:indexPath];
        return [_baseCell configureCellHeightWithItem:item];
    }
    
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
        
        id item = [self itemAtIndexPath:indexPath];
        
        FYBaseCell *cell = (FYBaseCell *)[self tableView:tableView cellForRowAtIndexPath:indexPath];
        [cell didSelectedWithItem:item];
        
        if (self.delegate && [self.delegate respondsToSelector:@selector(didSelectedCellWithItem:tableView:)]) {
            [self.delegate didSelectedCellWithItem:item tableView:tableView];
        }
        
    }
    
    - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
        
        if (self.delegate && [self.delegate respondsToSelector:@selector(heightForHeaderInSection:tableView:)]) {
            return [self.delegate heightForFooterInSection:section tableView:tableView];
        }
        
        return 1.0f;
    }
    
    - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{
        
        if (self.delegate && [self.delegate respondsToSelector:@selector(heightForFooterInSection:tableView:)]) {
            return [self.delegate heightForFooterInSection:section tableView:tableView];
        }
        
        return 1.0f;
    }
    
    - (nullable UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
        
        if (self.delegate && [self.delegate respondsToSelector:@selector(viewForHeaderInSection:tableView:)]) {
            return [self.delegate viewForHeaderInSection:section tableView:tableView];
        }
        
        return nil;
    }
    
    - (nullable UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section{
        
        if (self.delegate && [self.delegate respondsToSelector:@selector(viewForFooterInSection:tableView:)]) {
            return [self.delegate viewForFooterInSection:section tableView:tableView];
        }
        
        return nil;
    }
    

    * 3. 将某些逻辑移动到 Model 中 *

    下面有一个例子,在控制器中给 user 属性赋值一个列表属性:

    - (void)loadPriorities {
        NSDate* now = [NSDate date];
        NSString* formatString = @"startDate <= %@ AND endDate >= %@";
        NSPredicate* predicate = [NSPredicate predicateWithFormat:formatString, now, now];
        NSSet* priorities = [self.user.priorities filteredSetUsingPredicate:predicate];
        self.priorities = [priorities allObjects];
    }
    

    如果我们把这些逻辑交给 �User 来处理,控制器就会变得清洁了:

    - (void)loadPriorities {
        self.priorities = [self.user currentPriorities];
    }
    

    逻辑我们通过给 User 创建扩展 User+Extensions.m 来处理:

    - (NSArray*)currentPriorities {
        NSDate* now = [NSDate date];
        NSString* formatString = @"startDate <= %@ AND endDate >= %@";
        NSPredicate* predicate = [NSPredicate predicateWithFormat:formatString, now, now];
        return [[self.priorities filteredSetUsingPredicate:predicate] allObjects];
    }
    

    扩展阅读

    Lighter View Controller
    Clean Table View Code

    总结

    给控制器瘦身的方法还有很多,在这里就不一一说了,扩展阅读 介绍了不少,项目中如果用到的话可以节省不少开发时间,另外希望各位多多分享,共同进步.
    demo 地址

    相关文章

      网友评论

      本文标题:iOS开发之让控制器变得更轻量级

      本文链接:https://www.haomeiwen.com/subject/hlqdhttx.html