tableView是 iOS 開發(fā)中最常用的組件之一, Apple 用很好的代理模式將其解耦, 但我們開發(fā)人員卻將相應(yīng)的 Controller 變得臃腫不堪復(fù)用
就我目前的水平能想到, 盡一切力量簡化 Controller, 同時(shí)解耦的方法大約有以下幾種:
- 將 tableView 的 delegate, dataSource 從 Controller 中分離
- 將 tableViewCell 封裝, 不要將根據(jù)數(shù)據(jù)配置 cell 的操作寫著 cellForRow: 等方法中, 盡量封裝在 cell 中
這只是我能想到的兩點(diǎn), 代碼重構(gòu)這東西, 不想數(shù)學(xué)答案, 有唯一的標(biāo)準(zhǔn)答案, 不同的程序員有不同的解耦封裝方式, 所以以上兩點(diǎn)及本片文章僅代表個(gè)人觀點(diǎn), 看官看個(gè)過場就好了, 如果您覺得我說的有道理, 那當(dāng)然歡迎討論
廢話少說了, 如果最遵循了以上兩點(diǎn), 我們會(huì)發(fā)現(xiàn), Controller 內(nèi)容少了, 因?yàn)槲覀儗?tableView的 delegate, dataSource 分離出來, 但是如果一個(gè)界面中的 cell 不盡相同, 用在 storyboard 中的表現(xiàn)形式就是, 要拖上好幾種 cell 的樣式才嫩滿足頁面的需求, 好了這個(gè)是有在 cellForRow: 中就會(huì)有大量的 if-else if -else 了, 好吧可以用 Switch 替換 , 同樣如果每個(gè)不同的 cell有不同的點(diǎn)擊事件, 那么在 didSelect方法中, 又會(huì)有大量的 if-else if -else, 這樣的代碼后期很難維護(hù), 所以針對(duì)這個(gè)問題, 我要說下自己的想法了:
面向?qū)ο笕筇卣? 封裝, 繼承, 多態(tài), 在這里我們看來要用多態(tài)了, 所有的 cell 都是 tableViewCell, 但具體的可能會(huì)有差異, 所以我們會(huì)嘗試抽象共性, 在創(chuàng)建 cell 時(shí)就可以根據(jù)多態(tài)生成不同的 cell 了
細(xì)想, 起始 不同的cell在界面上提現(xiàn)就是界面上的不同, 在數(shù)據(jù)中就是數(shù)據(jù)的不同, 可以根據(jù)數(shù)據(jù)確定 cell, 看來數(shù)據(jù)要有抽象共性, 找出抽象共性后, 我們有兩種辦法可以實(shí)現(xiàn)多態(tài), 1. 將共性放到基類中, 使用繼承的方式 2. 使用接口; 設(shè)計(jì)模式告訴我們要面向接口編程, 而不是面向?qū)崿F(xiàn)編程, 所以我在這里的基類相當(dāng)于 java 中的抽象基類, 只有接口, 沒有實(shí)現(xiàn), 在這里我們使用接口吧
-
首先定義接口
#import <UIKit/UIKit.h> @protocol TableViewCellProtocol <NSObject> @optional /** * 注冊(cè) Cell 的 ID * * @return 注冊(cè) Cell 的 ID */ - (NSString *)registerCellIdentifier; /** * 對(duì)應(yīng) cell 的類, 在通過 xib, 代碼創(chuàng)建 cell 時(shí), 需要先注冊(cè), 能用到注冊(cè) Cell的 ID, 和 cell 類這兩個(gè)方法 * * @return 對(duì)應(yīng) cell 的類 */ - (Class)cellClass; /** * 點(diǎn)擊 cell 時(shí)觸發(fā)的操作 */ - (void)cellAction:(UITableView *)tableView; /** * cell 所在的 IndexPath */ - (NSIndexPath *)indexPath; @end
-
定義父 tableViewCell, 與接口建立聯(lián)系
#import <UIKit/UIKit.h> #import "TableViewCellProtocol.h" @interface ParentTableViewCell : UITableViewCell @property (nonatomic, strong) id<TableViewCellProtocol> data; @end #import "ParentTableViewCell.h" @implementation ParentTableViewCell @end
-
某個(gè) cell 數(shù)據(jù)的設(shè)置
- (NSString *)registerCellIdentifier { return @"AddressInfoCell"; } - (Class)cellClass { return [AddressInfo class]; } - (void)cellAction:(UITableView *)tableView { // TODO.. cellAction }
某個(gè)子 Cell 設(shè)置數(shù)據(jù)
- (void)setData:(id<TableViewCellProtocol>)data {
[super setData:data];
// 將 data 細(xì)化
if (data && [data isKindOfClass:[AddressInfoModel class]]) {
// TODO...
}
}
-
dataSource, delegate 實(shí)現(xiàn)
// 創(chuàng)建 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 中面向協(xié)議創(chuàng)建 Cell 這是我目前積累下來的, 如果以后有更好的方法, 會(huì)及時(shí)與大家分享, 我們的目標(biāo)是寫出可復(fù)用度高, 低耦合, 有美感的代碼, 我相信寫代碼也像做藝術(shù)一樣, 要肯想, 追求好的編碼方式
還是前面說的, 本片文章僅代表個(gè)人觀點(diǎn), 看官看個(gè)過場就好了, 如果您覺得我說的有道理, 那當(dāng)然歡迎討論, 希望能在代碼設(shè)計(jì)上更上一層樓
在 Swift 中面向協(xié)議成為一種必備的編程思想, 以后也會(huì)為大家代理關(guān)于 Swift 一些面向協(xié)議的內(nèi)容