控制器瘦身之Tableview抽取<二>

作者: 再见远洋 | 来源:发表于2016-10-27 12:03 被阅读300次

    demo地址:
    https://github.com/wxh794708907/YJYYTableViewDemo.git
    看这篇文章之前,我建议先看一下我的上一篇博客:http://www.jianshu.com/p/f3f0f2ef23a3

    上一篇博客就说过要讲一下tableView代理的抽取,今天来履行承诺了,如果上一篇还没看明白的小伙伴 我建议先花点时间理解下上一篇博客再看我接下来要讲的,因为上一篇只是个“前戏”。。。

    好吧,接下来进入主题,我们先来看下我们控制器中要写的代码:

    抽取效果

    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        [self.view addSubview:self.tableView];
    }
    
    #pragma mark- XXXXXXXXXXXXXXX懒加载XXXXXXXXXXXXXXXXXXXX
    /**
     *  tableView懒加载
     *
     *  @return tableView懒加载
     */
    - (YJYYTableView *)tableView {
        if (!_tableView) {
            _tableView =
            [[YJYYTableView alloc] initWithFrame:CGRectMake(0, 64, SCREENWIDTH, SCREENHEIGHT) style:UITableViewStylePlain];
            
            //数据源
            _tableView.sxDataSource = [YJYYDataSource dataSourceWith:self.dataArray dataConfigBlock:^(id cell, id model) {
                [cell configCellWithModel:model];
            }];
            
            //代理
            _tableView.sxDelegate = [YJYYDelegate delegate];
        }
        return _tableView;
    }
    
    /**
     *  数据源懒加载
     *
     *  @return 数据源
     */
    - (NSMutableArray *)dataArray {
        if (!_dataArray) {
            _dataArray = [NSMutableArray array];
            for (int i = 0 ; i<10; i++) {
                YJYYCustomModel * model = [[YJYYCustomModel alloc]init];
                [_dataArray addObject:model];
            }
        }
        return _dataArray;
    }
    

    不知道各位看官看完这一段代码什么感受,反正我是舒畅多了,至少不用再看见以前那一大堆不顺眼的代码了,机智的你一定注意到了关键的几句代码:

    //数据源
     _tableView.sxDataSource = [YJYYDataSource dataSourceWith:self.dataArray dataConfigBlock:^(id cell, id model) { [cell configCellWithModel:model]; }];
    
    //代理 
    _tableView.sxDelegate = [YJYYDelegate delegate];
    

    就是这两句代码,将我们原来的一大堆数据源和代理的方法给抽取出来了,数据源的抽取上一篇博客其实已经聊了比较多了,但是今天可能会继续对它开刀,主要的目的是配合代理的抽取,先看一段代码:

    //
    //  YJYYDataSource.h
    //  TableViewTest
    //
    //  Created by 遇见远洋 on 16/10/18.
    //  Copyright © 2016年 遇见远洋. All rights reserved.
    //
    
    #import <UIKit/UIKit.h>
    @class YJYYCustomModel,YJYYCustomCell;
    typedef void (^ConfigCellBlock)(id cell, id model);
    
    @protocol YJYYTableViewDataSource <UITableViewDataSource>
    
    @optional
    /**
     *  通过遵循这个协议的对象来返回数据模型
     *
     *  @param tableView tableView
     *  @param indexPath 索引
     *
     *  @return 数据模型
     */
    - (YJYYCustomModel *)tableView:(UITableView *)tableView objectForRowAtIndexPath:(NSIndexPath *)indexPath;
    
    /**
     *  通过遵循这个协议的对象来返回cell
     *
     *  @param tableView tableView
     *  @param object    模型
     *
     *  @return 自定义cell
     */
    - (YJYYCustomCell *)tableView:(UITableView*)tableView cellClassForObject:(YJYYCustomModel *)object;
    
    @end
    
    @interface YJYYDataSource : NSObject<YJYYTableViewDataSource>
    
    /**
     *  根据外界传入的数据以及标识返回一个数据源
     *
     *  @param dataArray  外界传入的数据
     *  @param identifier 标识符
     *  @param block      回调block用于配置cell数据
     *
     *  @return 数据源对象
     */
    + (instancetype)dataSourceWith:(NSArray <YJYYCustomModel *>*)dataArray dataConfigBlock:(ConfigCellBlock)block;
    
    @end
    

    这是原来抽取出来的数据源的头文件,不过和原来有一些差别的是我们增加了两个协议方法分别是:

    1.返回数据模型的方法;
    2.返回索引对应Cell的方法;

    可能你要问了,这两个协议方法到底有什么用呢?别着急,等我讲到代理的抽取,你就明白了,我们继续往下看。

    代理的抽取

    和数据源抽取的套路一样,我的想法是,继续在通过一个类处理原来在控制器中处理的代理方法,通过设置 self.tableView.delegate = "你自定义的代理类"来进行抽取;
    我们就以返回cell高度的方法来讲吧:

    - (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath {}
    

    可能你会和刚开始的我一样 直接在自定义的类中通过遵循UITableViewDelegate这个协议,然后将上面的方法实现就完事了,但是你会遇到如下的两个问题:

    1.我们怎么在这个方法中拿到数据(数据模型)?
    2.我们怎么在这个方法中拿到Cell?

    懵逼了吧,别着急,下面就告诉你如何来解决:
    我们要拿到数据模型,最好的方式是能够直接拿到数据源,这样我们就能拿到想要的数据了,那么cell怎么拿到呢?当然同样也是可以通过数据源来拿到的,如果不懂怎么拿的话,就继续往下看...

    还记得我前面埋下了一个疑问:为什么要在数据源中添加两个协议方法?这里我们就需要用到了,当然在这之前还需要解决一个问题,那就是代理的类怎么获取到数据源呢?或者说怎么让数据源和代理类之间产生联系?答案是----自定义UITableview----,下面就看代码吧:

    //
    //  YJYYTableView.h
    //  TableViewTest
    //
    //  Created by 遇见远洋 on 16/10/26.
    //  Copyright © 2016年 遇见远洋. All rights reserved.
    //
    
    #import <UIKit/UIKit.h>
    #import "YJYYDataSource.h"
    #import "YJYYDelegate.h"
    
    @interface YJYYTableView : UITableView<UITableViewDelegate>
    
    @property (nonatomic, strong) YJYYDataSource<YJYYTableViewDataSource> * sxDataSource/**<遵循了协议的数据源对象*/;
    
    @property (nonatomic, strong) YJYYDelegate * sxDelegate/**<代理对象*/;
    
    @end
    
    
    //
    //  YJYYTableView.m
    //  TableViewTest
    //
    //  Created by 遇见远洋 on 16/10/26.
    //  Copyright © 2016年 遇见远洋. All rights reserved.
    //
    
    #import "YJYYTableView.h"
    #import "YJYYCustomModel.h"
    #import "YJYYCustomCell.h"
    #import "YJYYDelegate.h"
    static NSString * const cellId = @"cellReuseIdentifier";
    
    @implementation YJYYTableView
    
    - (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style {
        self = [super initWithFrame:frame style:style];
        if (self) {
            self.showsVerticalScrollIndicator = YES;
            self.showsHorizontalScrollIndicator = NO;
            self.separatorStyle = UITableViewCellSeparatorStyleNone;
            [self registerClass:[YJYYCustomCell class] forCellReuseIdentifier:cellId];
        }
        return self;
    }
    
    - (void)setSxDataSource:(YJYYDataSource<YJYYTableViewDataSource> *)sxDataSource {
        if (_sxDataSource != sxDataSource) {
            _sxDataSource = sxDataSource;
            self.dataSource = sxDataSource;
        }
    }
    
    - (void)setSxDelegate:(YJYYDelegate *)sxDelegate {
        if (_sxDelegate != sxDelegate) {
            _sxDelegate = sxDelegate;
            self.delegate = sxDelegate;
        }
    }
    
    @end
    

    可能有些小伙伴还没有理解为什么需要通过自定义tableView来将他们联系起来,其实道理很简单,无论是在代理还是数据源我们都能拿到的对象是谁?就是tableView,那无疑肯定是通过tableView来建立联系,这也是最符合逻辑的,说完这个,接下来就是代理的抽取了,其实代理的抽取根数据源的抽取套路是一样的,只是代理需要跟数据源的协助,毕竟没有数据源 代理抽取也就没有意义了,下面看下代理类的代码:

    //
    //  YJYYDelegate.m
    //  TableViewTest
    //
    //  Created by 遇见远洋 on 16/10/26.
    //  Copyright © 2016年 遇见远洋. All rights reserved.
    //
    
    #import "YJYYDelegate.h"
    #import "YJYYCustomCell.h"
    #import "YJYYDataSource.h"
    #import "YJYYCustomModel.h"
    
    @interface YJYYDelegate ()
    
    @end
    
    @implementation YJYYDelegate
    //快速创建代理类
    + (instancetype)delegate {
        return [[self alloc]init];
    }
    
    #pragma mark - UITableViewDelegate
    
    - (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath {
        YJYYDataSource<YJYYTableViewDataSource> * dataSource = (id<YJYYTableViewDataSource>) tableView.dataSource;
        
        //通过数据源获取数据模型
        YJYYCustomModel *object = [dataSource tableView:tableView objectForRowAtIndexPath:indexPath];
        
        //通过数据源获取cell 的class
        YJYYCustomCell * cell = [dataSource tableView:tableView cellClassForObject:object];
        
        
        if (object.cellHeight == CellInvalidHeight) { //没有高度缓存的情况
            //计算cell高度
            object.cellHeight = [cell tableView:tableView rowHeightForObject:object];
        }
        return object.cellHeight;
    }
    
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
        //获取数据源对象
    //    YJYYDataSource<YJYYTableViewDataSource> * dataSource = (id<YJYYTableViewDataSource>) tableView.dataSource;
        
        //获取模型
    //    YJYYCustomModel * object = [dataSource tableView:tableView objectForRowAtIndexPath:indexPath];
        
        [tableView deselectRowAtIndexPath:indexPath animated:YES];
        NSLog(@"点击了第%ld个Cell",indexPath.row);
    }
    
    #pragma mark - 传递原生协议
    - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
       //这里是你要进行的操作
    }
    
    @end
    

    这里主要就讲两点,其实也就是数据源中添加的两个方法:
    1.返回数据模型的方法;
    2.返回cell的方法;
    这两个方法都是通过数据源来调用的,因为只有数据源最清楚数据,当然cell是你自己来决定的。

    最后的结束语

    这里并没有将所有的代码贴出来,例如数据源中添加的两个协议方法的实现、还有自定义模型、自定义Cell等 这些我觉得都放demo里了,有需要的自己去看吧,我都写了注释。不懂得就留言吧,还有文章的思路不一定是适合所有人的胃口,还望不喜勿喷。有什么好的想法可以多交流~~~~今天就写到这了,下篇文章再见.....

    相关文章

      网友评论

        本文标题:控制器瘦身之Tableview抽取<二>

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