1. UITableView的常规调用
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 10;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
MyStoreCell *cell=[tableView dequeueReusableCellWithIdentifier:@"storeCell"];
return cell;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 90.0;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
//移除
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
}
}
上面就是我们常规使用tableView的代码。在每次使用tableView的时候,我们都要写一大堆重复代理方法,不仅写着很烦,而且它如果放在控制器,让原本就臃肿的控制器便的更加臃肿。我们写代码的原则就是尽量避免重复的代码,那么是不是要想办法将这些代理方法抽取一下。怎么抽取呢?答案是block代替代理方法。我们知道block底层是函数,那么是oc的方法,我们就可以用block去取代它。再结合我的上篇文章OC 链式编程第一部分 - UI创建篇,也就是链式编程的思想,由此衍生出本篇文章链式调用tableView和collectionView。
本篇文章代码https://github.com/zfc769956454/ChainedDemo(下载下来运行ChainedDemo链式调用TableView和CollectionView这个target)
2. tableView的链式调用和分析
2.1 tableView的链式调用
这里我们先看看调用效果,代码如下:
__weak typeof(self)weakSelf = self;
[self.tableView configure:^(ZFC_TableViewChainedInvokeCreater *creater) {
creater.zfc_tableViewConfigure(tableViewConfig)
.zfc_numberOfSectionsInTableView(^NSInteger(UITableView *tableView){
return 3;
})
.zfc_numberOfRowsInSection(^NSInteger(UITableView *tableView,NSInteger section) {
return weakSelf.dataSource.count;
})
.zfc_heightForRowAtIndexPath(^CGFloat(UITableView *tableView,NSIndexPath *indexPath) {
return 50;
})
.zfc_cellForRowAtIndexPath(^(UITableView *tableView,__kindof ZFC_TableViewCell *cell, NSIndexPath *indexPath) {
cell.myLabel.text = [NSString stringWithFormat:@"%@%@",weakSelf.dataSource[indexPath.row],isXIB?@"->XIB":@""];
cell.contentView.backgroundColor = [UIColor grayColor];
})
.zfc_heightForHeaderInSection(^CGFloat(UITableView *tableView,NSInteger section) {
return 40;
})
.zfc_viewForHeaderInSection(^(UITableView *tableView,__kindof ZFC_TableViewHeaderFooterView *headerView,NSInteger section) {
headerView.myLabel.text = [NSString stringWithFormat:@"我是第-- %ld --段头%@",section,isXIB?@"->XIB":@""];
headerView.contentView.backgroundColor = [UIColor yellowColor];
})
.zfc_heightForFooterInSection(^CGFloat(UITableView *tableView,NSInteger section) {
return 40;
}).zfc_viewForFooterInSection(^(UITableView *tableView,__kindof ZFC_TableViewHeaderFooterView *footerView,NSInteger section) {
footerView.myLabel.text = [NSString stringWithFormat:@"我是第-- %ld --段尾%@",section,isXIB?@"->XIB":@""];
footerView.contentView.backgroundColor = [UIColor blueColor];
})
.zfc_deleteCellWithIndexPath(^(UITableView *tableView, NSIndexPath *indexPath) {
NSLog(@"删除");
[weakSelf.dataSource removeLastObject];
[tableView reloadData];
})
.zfc_didSelectRowAtIndexPath(^(UITableView *tableView,NSIndexPath *indexPath) {
NSLog(@"我点击了%@",weakSelf.dataSource[indexPath.row]);
});
}];
这样看起来是不是很爽,tableView的常用的代理方法一股气的.下去,看起来不仅美观,而且我们不用再每个用到tableView的地方去遵守协议方法、设置代理、写代理方法了。
2.2 核心部分分析
这里我就以第一个链式调用zfc_numberOfSectionsInTableView来分析,其它的思路都相似,先上这段代码的实现
(1)在ZFC_TableViewChainedInvokeCreater这个类中定义属性
/**
返回section数量
*/
typedef ZFC_TableViewChainedInvokeCreater *(^ZFC_numberOfSectionsInTableView)(NSInteger(^)(UITableView *tableView));
/** section数量 */
@property (nonatomic,readonly) ZFC_numberOfSectionsInTableView zfc_numberOfSectionsInTableView;
(2)在ZFC_TableViewChainedInvokeCreater.m中申明一个属性block->numberOfSectionsInTableViewHandle用来保存外界传来的section调用的block,也就是zfc_numberOfSectionsInTableView(A)的参数
/** section数量--保存用的block */
@property (nonatomic,copy)NSInteger (^numberOfSectionsInTableViewHandle)(UITableView *tableView) ;
//重写getter方法
- (ZFC_numberOfSectionsInTableView)zfc_numberOfSectionsInTableView {
return ^ZFC_TableViewChainedInvokeCreater *(NSInteger (^sectionsHandle)(UITableView *tableView)) {
self.numberOfSectionsInTableViewHandle = sectionsHandle;
return self;
};
}
(3)在tableView返回section的代理方法中执行(2)中保存的block->numberOfSectionsInTableViewHandle
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
if(self.numberOfSectionsInTableViewHandle) return self.numberOfSectionsInTableViewHandle(tableView);
return 0;
}
(4)下面我们来看一下执行过程
第一步:调用zfc_numberOfSectionsInTableView(实参A),此处实参A是一个block,如下
//实参A
^NSInteger(UITableView *tableView){
return 3;
}
第二步:在ZFC_TableViewChainedInvokeCreater.m中重写了get方法,它的返回值是一个block->也就是zfc_numberOfSectionsInTableView,zfc_numberOfSectionsInTableView的参数是一个block->也就是上面的实参A,在这个getter方法中,用一个block->numberOfSectionsInTableViewHandle来保存这个实参
第三步:在tableView的代理方法中执行上一步保存numberOfSectionsInTableViewHandle->也就是实参A
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
if(self.numberOfSectionsInTableViewHandle) return self.numberOfSectionsInTableViewHandle(tableView);
return 0;
}
第四步:上一步执行了block后,就会回调到下面的block内
.zfc_numberOfSectionsInTableView(^NSInteger(UITableView *tableView){
//第三步完了会回调到这里,此处返回结果
return 3;
})
第五步:当第四步中的block回调完了,因为它是一个有返回值的block,所以它的返回值又会被numberOfSectionsInTableView方法接受,这样就返回了tableView有多少段
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
//此处接受*numberOfSectionsInTableViewHandle*的返回结果
if(self.numberOfSectionsInTableViewHandle) return self.numberOfSectionsInTableViewHandle(tableView);
return 0;
}
以上就是zfc_numberOfSectionsInTableView的主要实现过程
3. collectionView的链式调用
collectionView的链式调用思想和上面的tableView的思想一样,而且调用方式也差不多,核心代码如下
__weak typeof(self)weakSelf = self;
[self.collectionView configure:^(ZFC_CollectionViewChainnedInvokeCreater *creater) {
creater.zfc_collectionViewConfigure(collectionViewConfig)
.zfc_numberOfSectionsInCollectionView(^NSInteger(UICollectionView *collectionView){
return 3;
})
.zfc_numberOfItemsInSection(^NSInteger(UICollectionView *collectionView,NSInteger section) {
return weakSelf.dataSource.count;
})
.zfc_sizeForItemAtIndexPath(^CGSize(UICollectionView *collectionView,NSIndexPath *indexPath) {
return CGSizeMake(115 , 100);
})
.zfc_cellForItemAtIndexPath(^(UICollectionView *collectionView,__kindof ZFC_CollectionViewCell *cell, NSIndexPath *indexPath) {
cell.myLabel.text = [NSString stringWithFormat:@"%@%@",weakSelf.dataSource[indexPath.row],isXIB?@"->XIB":@""];
cell.contentView.backgroundColor = [UIColor redColor];
})
.zfc_referenceSizeForHeaderInSection(^CGSize(UICollectionView *collectionView, NSInteger section) {
return CGSizeMake(200, 40);
})
.zfc_collectionElementKindSectionHeader(^(UICollectionView *collectionView, __kindof ZFC_CollectionHeaderFooterView *sectionHeaderView, NSInteger section) {
sectionHeaderView.myLabel.text = [NSString stringWithFormat:@"我是第-- %ld --段头%@",section,isXIB?@"->XIB":@""];
sectionHeaderView.myView.backgroundColor = [UIColor greenColor];
})
.zfc_referenceSizeForFooterInSection(^CGSize(UICollectionView *collectionView, NSInteger section) {
return CGSizeMake(200, 40);
})
.zfc_collectionElementKindSectionFooter(^(UICollectionView *collectionView, __kindof ZFC_CollectionHeaderFooterView *sectionFooterView, NSInteger section) {
sectionFooterView.myLabel.text = [NSString stringWithFormat:@"我是第-- %ld --段尾%@",section,isXIB?@"->XIB":@""];
sectionFooterView.myView.backgroundColor = [UIColor darkGrayColor];
})
.zfc_didSelectItemAtIndexPath(^(UICollectionView *collectionView, NSIndexPath *indexPath) {
NSLog(@"我点击了%@",weakSelf.dataSource[indexPath.row]);
});
}];
4. 几个注意的地方
(1)在调用前,需要配置tableView和collectionView,在这个配置类,针对cell、sentionHeaderView、sectionFooterView的创建是支持xib创建的,但是如果是xib创建需要将对应的变量isCellXib、isSectionHeaderXib、isSectionFooterXib设置为YES
(2)在config里面还需要传入cellClass、sectionHeaderClass、sectionFooterClass用于内部注册使用
(3)tableView的配置示例:
__block BOOL isXIB = YES;
ZFC_TableViewConfig *tableViewConfig = [ZFC_TableViewConfig new];
tableViewConfig.tableView = self.tableView;
tableViewConfig.isCellXib = isXIB;
tableViewConfig.cellClass = [getClassFromClassString(@"ZFC_TableViewCell", isXIB) class];
tableViewConfig.isSectionHeaderXib = isXIB;
tableViewConfig.sectionHeaderClass = [getClassFromClassString(@"ZFC_TableViewHeaderFooterView", isXIB) class];
tableViewConfig.isSectionFooterXib = isXIB;
tableViewConfig.sectionFooterClass = [getClassFromClassString(@"ZFC_TableViewHeaderFooterView", isXIB) class];
tableViewConfig.canDelete = YES;
(4)collectionView的配置示例:
__block BOOL isXIB = YES;
ZFC_CollectionConfig *collectionViewConfig = [ZFC_CollectionConfig new];
collectionViewConfig.collectionView = self.collectionView;
collectionViewConfig.isCellXib = isXIB;
collectionViewConfig.cellClass = [getClassFromClassString(@"ZFC_CollectionViewCell", isXIB) class];
collectionViewConfig.isSectionHeaderXib = isXIB;
collectionViewConfig.sectionHeaderClass = [getClassFromClassString(@"ZFC_CollectionHeaderFooterView", isXIB) class];
collectionViewConfig.isSectionFooterXib = isXIB;
collectionViewConfig.sectionFooterClass = [getClassFromClassString(@"ZFC_CollectionHeaderFooterView", isXIB) class];
5. 总结
以上就是tableView和collectionView的链式调用部分。最后,我再提一下链式创建UI和使用的小工具库ZFCChainedCreater,支持pod导入pod 'ZFCChainedCreater', '~> 1.0.2',github地址:https://github.com/zfc769956454/ZFCChainedCreater