tableView是 iOS 开发中最常用的组件之一, Apple 用很好的代理模式将其解耦, 但我们开发人员却将相应的 Controller 变得臃肿不堪复用
就我目前的水平能想到, 尽一切力量简化 Controller, 同时解耦的方法大约有以下几种:
- 将 tableView 的 delegate, dataSource 从 Controller 中分离
- 将 tableViewCell 封装, 不要将根据数据配置 cell 的操作写着 cellForRow: 等方法中, 尽量封装在 cell 中
这只是我能想到的两点, 代码重构这东西, 不想数学答案, 有唯一的标准答案, 不同的程序员有不同的解耦封装方式, 所以以上两点及本片文章仅代表个人观点, 看官看个过场就好了, 如果您觉得我说的有道理, 那当然欢迎讨论
废话少说了, 如果最遵循了以上两点, 我们会发现, Controller 内容少了, 因为我们将 tableView的 delegate, dataSource 分离出来, 但是如果一个界面中的 cell 不尽相同, 用在 storyboard 中的表现形式就是, 要拖上好几种 cell 的样式才嫩满足页面的需求, 好了这个是有在 cellForRow: 中就会有大量的 if-else if -else 了, 好吧可以用 Switch 替换 , 同样如果每个不同的 cell有不同的点击事件, 那么在 didSelect方法中, 又会有大量的 if-else if -else, 这样的代码后期很难维护, 所以针对这个问题, 我要说下自己的想法了:
面向对象三大特征: 封装, 继承, 多态, 在这里我们看来要用多态了, 所有的 cell 都是 tableViewCell, 但具体的可能会有差异, 所以我们会尝试抽象共性, 在创建 cell 时就可以根据多态生成不同的 cell 了
细想, 起始 不同的cell在界面上提现就是界面上的不同, 在数据中就是数据的不同, 可以根据数据确定 cell, 看来数据要有抽象共性, 找出抽象共性后, 我们有两种办法可以实现多态, 1. 将共性放到基类中, 使用继承的方式 2. 使用接口; 设计模式告诉我们要面向接口编程, 而不是面向实现编程, 所以我在这里的基类相当于 java 中的抽象基类, 只有接口, 没有实现, 在这里我们使用接口吧
-
首先定义接口
#import <UIKit/UIKit.h> @protocol TableViewCellProtocol <NSObject> @optional /** * 注册 Cell 的 ID * * @return 注册 Cell 的 ID */ - (NSString *)registerCellIdentifier; /** * 对应 cell 的类, 在通过 xib, 代码创建 cell 时, 需要先注册, 能用到注册 Cell的 ID, 和 cell 类这两个方法 * * @return 对应 cell 的类 */ - (Class)cellClass; /** * 点击 cell 时触发的操作 */ - (void)cellAction:(UITableView *)tableView; /** * cell 所在的 IndexPath */ - (NSIndexPath *)indexPath; @end
-
定义父 tableViewCell, 与接口建立联系
#import <UIKit/UIKit.h> #import "TableViewCellProtocol.h" @interface ParentTableViewCell : UITableViewCell @property (nonatomic, strong) id<TableViewCellProtocol> data; @end #import "ParentTableViewCell.h" @implementation ParentTableViewCell @end
-
某个 cell 数据的设置
- (NSString *)registerCellIdentifier { return @"AddressInfoCell"; } - (Class)cellClass { return [AddressInfo class]; } - (void)cellAction:(UITableView *)tableView { // TODO.. cellAction }
某个子 Cell 设置数据
- (void)setData:(id<TableViewCellProtocol>)data {
[super setData:data];
// 将 data 细化
if (data && [data isKindOfClass:[AddressInfoModel class]]) {
// TODO...
}
}
-
dataSource, delegate 实现
// 创建 Cell - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSArray *subArr = self.datas[indexPath.section]; id<TableViewCellProtocol> model = subArr[indexPath.row]; ParentTableViewCell *cell = (ParentTableViewCell *)[tableView dequeueReusableCellWithIdentifier:[model registerCellIdentifier] forIndexPath:indexPath]; cell.data = model; return cell; } // cell 操作 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:YES]; NSArray *subArr = self.datas[indexPath.section]; id<TableViewCellProtocol> model = subArr[indexPath.row]; if (model && [model respondsToSelector:@selector(cellAction:)]) { [model cellAction:tableView]; } }
在 OC 中面向协议创建 Cell 这是我目前积累下来的, 如果以后有更好的方法, 会及时与大家分享, 我们的目标是写出可复用度高, 低耦合, 有美感的代码, 我相信写代码也像做艺术一样, 要肯想, 追求好的编码方式
还是前面说的, 本片文章仅代表个人观点, 看官看个过场就好了, 如果您觉得我说的有道理, 那当然欢迎讨论, 希望能在代码设计上更上一层楼
在 Swift 中面向协议成为一种必备的编程思想, 以后也会为大家代理关于 Swift 一些面向协议的内容