iOS寫的比較多的就是UITableView,幾乎每個控制器里面都有這家伙,在加上網絡請求,錯誤處理,loading動畫,UITableViewDataSource,UITableViewDelegate,一個控制器還沒怎么寫就已經大篇的代碼了。
當然,大部分人是不會把這些都寫在控制器里然后一遍一遍的粘貼的。解決方法有很多,繼承算是常用的一種,或者利用協議的特性也可以達到目的
什么是協議編程
協議的話想對更靈活,定義一個規則,別人可以遵守這個協議,然后實現規定的方法,同時一個類可以有多個協議。
但是這些協議只是相當于接口,遵循某個協議的類只表明實現了這些接口,每個類都需要對這些接口有單獨的實現,這就很可能會導致重復代碼的產生。我們可以利用一些工具,為協議添加默認的實現,比如說ProtocolKit, 或者libextobjc里面的EXTConcreteProtocol.h
。后面講大致原理
為什么要用它
下面是個人的淺顯理解,理解的錯誤的地方請輕拍:
我們使用協議的目的,更加靈活,從而降低耦合性,減少冗余性(你可以實現,也可以不實現)。
相比OC,目前Swift里面有很多地方用到協議編程,說明它是一種比較推薦的編程方式
怎么用
本人結合作者的開發經驗,講一講我對協議編程的理解和具體的使用,我們就拿常見的帶UITableView
控制器來舉例
我們的目的:減低重復代碼,增加可擴展性
細化一下:
- 把網絡和網絡的loading,放到
RequestViewController
控制器里面 - 一個
BaseTableViewController
繼承RequestViewController
,同時把UITableViewDataSource,UITableViewDelegate
方法寫到這里面 - 使用一個接口請求以及數據處理的類,里面進行具體的網絡請求和請求結果的處理
這樣一個控制器里面,就剩下一些自己特定的響應事件、除了UITableView
的其它的UI組件,以及少部分cell代理或者數據源方法,這些也可以抽出去
下面是我從項目沖抽出來的一個Demo的代碼片段
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor whiteColor];
[self loadData];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 44;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
id obj = [self.viewModel objectAtIndexPath:indexPath];
// TODO 裝配數據--通常情況下,我們會用一個分類來進行cell注冊和取
static NSString *ID = @"ID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
}
// Configure the cell...
cell.textLabel.text = @"ticsmatic";
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
id obj = [self.viewModel objectAtIndexPath:indexPath];
// TODO 處理點擊事件
}
小Demo在這里ConcreteProtocol
補充
簡單的講一下協議的默認實現方式,看ProtocolKit就知道,大約也就200行代碼。讓你分析一下,一句話就是為類增加方法被唄。把協議的默認實現方法,注入到遵守這個協議的類里面,必然是利用runtime。
具體代碼講解可以看這篇博文如何在 Objective-C 中實現協議擴展
最后
這個Demo寫的比較粗糙,僅僅是提供一種思路,里面還有許多可以優化修改的地方。同時,如果我在那里寫的不好的可以批評指正