iOS实现UITableViewDataSource与Controller的分离

写在前面

在之前的项目中好多处用到了tableView,然而之前不懂得将代理方法实现分离,所以每在一处用到tableView就要在controller中写一遍UITableViewDataSource和UITableViewDelegate,实现tableView的基本功能中用到的tableViewDelegate的方法还算不太多,但是说到UITableViewDataSource,里面就那些固定的用法,每次都要写一遍,大大增加了代码的冗余度,虽然不吝啬体力多写几行代码,但是给人感觉不太好,接下来就来说一下怎么样将tableViewDataSource这个磨人的小妖精从controller中分离出来。

创建一个基于NSObject的ArrayDataSource类

这个类就是我们将UITableViewDataSource分离出来所封装的类。继承协议@interface ArrayDataSource : NSObject<UITableViewDataSource>
OK,开始我们的分离之路:

1、

首先在.h文件中,我们定义一个block:typedef void (^TableViewCellConfigureBlock)(id cell, id items);
block中需要的两个参数:第一个参数是cell,第二个参数是数据(这个数据可以是model或者字典)。

2、

在.h文件中写两个作为外部调用的接口:
第一个函数:

@param anItems             传入的盛装数据的数组
 @param aCellIdentifier     cell的标示符
 @param aConfigureCellBlock 回调的block

- (id)initWithItems:(NSArray *)anItems
     cellIdentifier:(NSString *)aCellIdentifier
 configureCellBlock:(TableViewCellConfigureBlock)aConfigureCellBlock;

第二个函数:
将传入数组中的数据按照cell的indexPath使用(这个我不知道怎么表述清楚,这个方法就是之前在- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath这个函数中将数组中的数据根据cell的索引值给cell中的控件赋值,不知道这样说能不能引起大家的共鸣……^_^)

- (id)itemAtIndexPath:(NSIndexPath *)indexPath;
3、

在.m中,我们声明三个全局变量:

@interface ArrayDataSource ()

@property(nonatomic, strong) NSArray* items;/**< array */
@property(nonatomic, copy) NSString* cellIdentifier;/**< cellIdentifier */
@property(nonatomic, copy) TableViewCellConfigureBlock configureCellBlock;/**< block */

@end

实现.h中的方法:

- (instancetype)init {
    return  nil;
}

调用初始化方法时将外部数据赋值给内部参数
- (id)initWithItems:(NSArray *)anItems cellIdentifier:(NSString *)aCellIdentifier configureCellBlock:(TableViewCellConfigureBlock)aConfigureCellBlock {

    self = [super init];
    if (self) {
        self.items = anItems;
        self.cellIdentifier = aCellIdentifier;
        self.configureCellBlock = aConfigureCellBlock;
    }
    return  self;
}
根据cell的索引值,将传入的数据分离
- (id)itemAtIndexPath:(NSIndexPath *)indexPath {
    return self.items[(NSUInteger) indexPath.row];
}
#pragma mark - UITableViewDataSource
实现UITableViewDataSource的方法。。

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.items.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:self.cellIdentifier];
    id item = [self itemAtIndexPath:indexPath];
//在这儿将block传出。
    self.configureCellBlock(cell, item);
    return cell;
}
在Controller中使用

OK,以上的这个类就是我们分离出来的DataSource的类了

在controller中我使用的假数据,将数据放在一个数组arr中,这里我用到了懒加载,在这里我遇到一个困惑就是为什么在if (!_arr)条件判断中不能使用self.arr,而只能用_arr,但是在if (!_arr) { self.arr = @[@{@"name":@"实现tableViewController的瘦身"}}]; }中却可以使用self.arr. 我查了一下资料找到答案,_arr是直接值访问,而self.arr是属性访问,就是通过get/set方法来读取这个值,xcode会默认将两个值通过syncthesize关键字进行同步,- (NSArray *)arr这个方法就是self.arr的get方法,也就是说每次你调用self.arr的时候都会进入这个方法,如果在这个方法里用了下面这个语句if (!self.arr );逻辑上是行不通的,因为在这里调用self.arr他会再一次进入这个方法,理论上就会死循环,而_arr是直接值访问的,他不会调用get/set方法,所以就不会有这个问题.
那在if (!_arr) { self.arr = @[@{@"name":@"实现tableViewController的瘦身"}}]; }中使用self.arr,虽然他也会进入get方法,但是他已经不等于nil了.会直接返回他本身,所以没有问题.

- (NSArray *)arr {

    if (!_arr) {
        self.arr = @[@{@"name":@"实现tableViewController的瘦身"}}];
    }
    return _arr;
}

我们在controller中使用tableView的时候需要这样做:

- (void)createTableView {

    self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
    [self.tableView registerClass:[LGJTableViewCell class] forCellReuseIdentifier:@"cell"];

    self.tableView.rowHeight = 70;
    [self.view addSubview:self.tableView];
    //这里我将block中的第二个参数(id items)传入了一个字典。因为我的数据是存放在数组中的字典中的。
    TableViewCellConfigureBlock configureCell =^(LGJTableViewCell *cell, NSDictionary *dic) {
        //在这里操作cell中的控件,或者给cell中的控件赋值
        [cell configData:dic];
    };
    self.dateSource = [[ArrayDataSource alloc] initWithItems:self.arr cellIdentifier:@"cell" configureCellBlock:configureCell];
    self.tableView.dataSource = self.dateSource;
}
总结

经过抽取,我们将dataSource从controller中分离出来,这样不用每次使用tableView的时候我们都要重复写一遍dataSource代理了,同时也简化了代码结构。希望小伙伴们如果觉得有不妥的地方帮我指出来,我们一同进步。end



文/irmbeu(简书作者)
原文链接:http://www.jianshu.com/p/ee6b57fc335e
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
posted @ 2016-12-20 20:25  周希  阅读(1595)  评论(0编辑  收藏  举报