轻量化ViewControllers顾名思义就是把ViewController的代码进行简化让控制器更简单更清晰
把DataSource和其他protocol分离出控制器
因为做项目很多控制器都TableViewController,所以必须要有数据源(TableViewDataSource)输入,一般DataSource的3个方法都在控制器里
我们的目的就是要把他分离出来,方法就是自定义一个类,然后控制器调用这个类并且这个数据源类是通用的,别的TableViewController或者有定义了tableView/collectionView的控制器都可以调用自定义ArrayDataSource类
1.定义一个Block,用于传递cell和数据
1
| typedef void (^TableViewCellPassBlock)(id cell, id item);
|
2.定义一个方法给控制器调用,用于初始化ArrayDataSource类(需要暴露在.h文件中)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @property (nonatomic, strong) NSArray *items; @property (nonatomic, copy) NSString *cellIdentifier; @property(nonatomic, copy) TableViewCellPassBlock passBlock; /**
* 初始化数据源的方法 * @param anItems 用于接受数据的数组 * @param aCellIdentifier 接收cell的ID * @param aPassBlock 接收传递的Block */ - (id)initWithItems:(NSArray *)anItems cellIdentifier:(NSString *)aCellIdentifier passBlock(TableViewCellPassBlock)aPassBlock { self = [super init]; if(self){ self.items = anItems; self.cellIdentifier = aCellIdentifier; self.passBlock = [aPassBlock copy]; } return self; }
|
3.然后就是数据源的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| /** 这个方法找出数组的数据 后面要用到*/ - (id)itemAtIndexPath:(NSIndexPath *)indexPath { return self.items[(NSUInteger) indexPath.row]; }
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.items.count; }
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: self.cellIdentifier forIndexPath: indexPath]; id item = [self itemAtIndexPath: indexPath]; self.passBlock(cell, item); return cell; }
|
ArrayDataSource类就这样定义完成了
接下来是控制器的调用
只需要写以下几行代码便可以设置tableView的数据源,不用每个控制器都写那三个方法
1 2 3 4 5 6 7 8 9 10
| //数组传数据是接下来要简化的,后面会详细说明 NSArray *arr = [AppDelegate sharedDelegate].returnModel.returnData; //使用Block回调,传递cell和模型数据 TableViewCellPassBlock passBlock = ^(TestModelCell *cell,TestModel *model){ //测试方法,只是传递model给cell,这个方法用分类写的,自定义cell的分类 [cell setName: model]; }; //初始化并设置tableView的数据源 self.dataSource = [[ArrayDataSource alloc] initWithItems: arr cellIdentifier:@"TestModelCell" passBlock: passBlock]; self.tableView.dataSource = self.dataSource;
|
二、将业务逻辑放到model中
一些跟控制器无关的代码可以放到模型中
测试代码我写了一个TestModel,只有一个属性和一个初始化方法
1 2 3
| @property (nonatomic, copy) NSString *name;
- (instancetype)initWithName:(NSString *)name;
|
然后又写了一个model,因为要返回数据所以我叫ReturnModel
在.h文件中暴露的方法
1 2 3 4 5
| //类方法,创建的时候用这个方法 + (instancetype)returnModel;
//这个方法用于返回数据 - (NSArray *)returnData;
|
然后在.m文件中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| + (instancetype)returnModel { return [[self alloc] init]; }
- (id)init { self = [super init]; if (self) { //调用方法执行业务逻辑的方法 [self doSomething]; } return self; }
//可以在这个方法中执行与控制器无关的业务逻辑 - (void)doSomething { NSLog(@"try to do something"); }
//在这个方法中返回模型数据,数据略
- (NSArray *)returnData { NSArray *array = [[NSArray alloc] initWithObject:...]; return array; }
|
思路就是在返回数据的模型类中执行业务逻辑,在创建类的时候执行
在AppDelegate中添加方法和属性,并且暴露在.h文件中
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| + (instancetype)sharedDelegate { return [UIApplication sharedApplication].delegate; }
@synthesize returnModel = _returnModel;
- (ReturnModel *)returnModel { if (_returnModel == nil) { _returnModel = [ReturnModel returnModel]; } return _returnModel; }
|
所以控制器直接调用方法得到数据
1
| NSArray *arr = [AppDelegate sharedDelegate].returnModel.returnData;
|
这时候控制器已经很简化了
可以把网络请求也放在model层
参考
Obj中国的#1
探索
文中只写了3钟方法,后来我在用的时候要用到其他数据源方法的时候想,为什么不把其他方法也写进去。
把数据源完全分离开来。
例如 Section的title
接口方法
1
| - (void)setSelectIndexTitle:(NSArray *)selectIndexTitles;
|
用一个数据接收便可
1 2 3 4
| - (void)setSectionTitle:(NSArray *)groupTitles { self.groupTitles = groupTitles; }
|
然后在titleForHeaderInSection中调用即可
1 2 3 4 5
| - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { NSString *title = self.groupTitles[section]; return title; }
|