Lighter your ViewController-打造轻量化ViewController

前言

随着业务的不断迭代,一些较大的业务模块的ViewController变得极为臃肿,越来越难以维护。为ViewController瘦身变成的越来越迫切。
提供一些思路供大家参考。

1.Separate out UITableViewDataSource and UITableViewDelegate

剥离DataSource和其他Protocols
这个方法最早见于objc.io上。将UITableViewDatasource相关的代码从ViewController中抽取并封装到其他类中。也相对提高重用性。
然后我在一个较大的业务中尝试使用了。感觉效果一般。
示例工程中,有一个类PhotosViewController,里面原本有如下3个方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# pragma mark Pragma 

- (Photo*)photoAtIndexPath:(NSIndexPath*)indexPath {
return photos[(NSUInteger)indexPath.row];
}

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

- (UITableViewCell*)tableView:(UITableView*)tableView
cellForRowAtIndexPath:(NSIndexPath*)indexPath {
PhotoCell* cell = [tableView dequeueReusableCellWithIdentifier:PhotoCellIdentifier forIndexPath:indexPath];
Photo* photo = [self photoAtIndexPath:indexPath];
cell.label.text = photo.name;
return cell;
}
如下代码所示,这里通过一个block来配置UITableViewCell,当然,也可以使用delegate对UITableViewCell进行配置,这主要取决于开发者。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@implementation ArrayDataSource 

- (id)itemAtIndexPath:(NSIndexPath*)indexPath {
return items[(NSUInteger)indexPath.row];
}

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

- (UITableViewCell*)tableView:(UITableView*)tableView
cellForRowAtIndexPath:(NSIndexPath*)indexPath {
id cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
id item = [self itemAtIndexPath:indexPath];
configureCellBlock(cell,item);
return cell;
}

@end
可以把ViewController中的那3个方法移除掉,并创建自定义类的一个示例对象,然后将其设置为table view的data source,如下代码所示。
1
2
3
4
5
6
7
8
9
10
...
{
void (^configureCell)(PhotoCell*, Photo*) = ^(PhotoCell* cell, Photo* photo) {
cell.label.text = photo.name;
};
photosArrayDataSource = [[ArrayDataSource alloc] initWithItems:photos
cellIdentifier:PhotoCellIdentifier
configureCellBlock:configureCell];
self.tableView.dataSource = photosArrayDataSource;
}

2.Category

大体思路:根据当前业务,将业务拆分为多个小模块。创建多个Category,每个Category处理自己业务模块逻辑。
目录结构如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
...
OrderViewController.h
OrderViewController.m
OrderViewController+NetRequest.h
OrderViewController+NetRequest.m
OrderViewController+DataReport.h
OrderViewController+DataReport.m
OrderViewController+Address.h
OrderViewController+Address.m
OrderViewController+Shipping.h
OrderViewController+Shipping.m
OrderViewController+Invoice.h
OrderViewController+Invoice.m
OrderViewController+Wallet.h
OrderViewController+Wallet.m
...
上面目录结构是电商的订单提交页面,主体功能可以分为订单地址、配送信息、发票、钱包等业务场景,再将网络请求、数据上报等功能抽离到相应Category,实现代码分离。减少主ViewController大小。
其实还是比较简单有效的方法。如果要说弊端,那最多可能稍微拖慢App加载速度吧。

3.模块化调用

将一些业务逻辑处理封装到其他类中,由ViewController去调用这些类。即:不要在ViewController中做一些复杂的逻辑处理,由其他类代理处理

比如:

  • 业务Model自己逻辑自己处理。VC只负责调用。
  • 网络请求、数据处理服务创建相应Manager类处理。
  • 复杂的View结构通过添加子ViewController实现。
  • 使用KVO。比如你创建一个列表,数据需要通过网络请求刷新[webservice fetchNewData],通过KVO可以实现多个网络请求的自动刷新。

总结

这些只是可供大家参考的方法,目的是为了编写方便维护的、可读性高的代码。
写于2015-01-19