demo地址:
https://github.com/wxh794708907/YJYYTableViewDemo.git
看这篇文章之前,我建议先看一下我的上一篇博客://www.greatytc.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里了,有需要的自己去看吧,我都写了注释。不懂得就留言吧,还有文章的思路不一定是适合所有人的胃口,还望不喜勿喷。有什么好的想法可以多交流~~~~今天就写到这了,下篇文章再见.....