在搭建APP靜態TableView界面時,都是每一個vc對應建立一個UITableView,而後實現UITableViewDataSource、UITableViewDelegate等方法,這樣的開發方式有幾大弊端:
1)效率不高,每一個界面都得建立,實現協議。
2)cell的點擊事件區分時須要一大堆的if/else。
3)界面元素變化時,維護起來很是蛋疼,須要修改好幾個地方的if/else。
在分析完微信後,發現微信搭建靜態TableView頁面時,並不會出現上面幾個問題,搭建很是easy,因此決定將學習到的思路分享出來你們一塊兒交流學習。git
1.一臺越獄的5s
2. dumpdecrypted(砸殼)
3.class-dump(導出頭文件)
4.IDA(反彙編)
5.cycript(調試)github
逆向的基礎知識就不概述了,本文章主要是對微信進行靜態分析數組
經過觀察多個靜態頁面的vc,發現vc裏沒有直接建立UITableView,而是經過MMTableViewInfo這個類建立的,MMTableViewInfo裏有個_tableView成員變量,並實現了UITableViewDataSource、UITableViewDelegate,因此無誤。下圖是MMTableViewInfo頭文件截圖部份內容:bash
經過觀察,很容易看出MMTableViewInfo中的成員變量_arrSections是_tableView的數據源,調試打印其元素是MMTableViewSectionInfo對象。下圖是MMTableViewSectionInfo頭文件截圖部份內容:微信
經過觀察,猜想MMTableViewSectionInfo中的_arrCells應該是每一個section中的cell數組,調試打印其元素是MMTableViewCellInfo對象。下圖是MMTableViewCellInfo頭文件截圖部份內容:ide
1.觀察MMTableViewCellInfo頭文件,經過fCellHeight、cellStyle、accessoryType、+ (id)normalCellForTitle:(id)arg1 rightValue:(id)arg2這幾個屬性和方法,應該能夠想到,這個類就是爲cell準備數據的。工具
2.觀察MMTableViewSectionInfo頭文件,- (void)addCell:(id)arg1;
經過該方法添加cellInfo到_arrCells裏構成了一個組的數據學習
3.觀察MMTableViewInfo頭文件,- (void)addSection:(id)arg1
,能夠想到是添加sectionInfo到_arrSections裏構成了UITableView的數據源ui
接下來經過IDA反彙編工具,查看每一個類具體實現的僞代碼spa
先看下僞代碼(因封裝的方法較多,這裏只分析一個方法):
分析轉化爲oc代碼是這樣的,類名前綴我使用了LY,注意:demo裏對基礎的cellInfo作了一層封裝。 第二個方法有SEL和target,這裏是微信對cell的選中事件進行了處理,使用了target/action方式,因此監聽cell的點擊時不須要使用代理,使得每一個cell有本身的action,即作到了解耦,又不用寫一堆的if/else了。這個類的實現相對簡單,如今只看cell是如何添加的。
///添加cell
- (void)addCell:(LYTableViewCellInfo *)cell{
[_arrCells addObject:cell];
}
複製代碼
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return _arrSections.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
LYTableViewSectionInfo *sectionInfo = _arrSections[section];
return [sectionInfo getCellCount];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
LYTableViewSectionInfo *sectionInfo = _arrSections[indexPath.section];
LYTableViewCellInfo *cellInfo = [sectionInfo getCellAt:indexPath.row];
return cellInfo.fCellHeight;
}
複製代碼
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
LYTableViewSectionInfo *sectionInfo = _arrSections[indexPath.section];
LYTableViewCellInfo *cellInfo = [sectionInfo getCellAt:indexPath.row];
NSString *iden = [NSString stringWithFormat:@"LYTableViewInfo_%zd_%zd", indexPath.section, indexPath.row];
LYTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:iden];
if (!cell) {
cell = [[LYTableViewCell alloc] initWithStyle:cellInfo.cellStyle reuseIdentifier:iden];
}
cell.accessoryType = cellInfo.accessoryType;
cell.selectionStyle = cellInfo.selectionStyle;
cell.textLabel.text = [cellInfo getUserInfoValueForKey:@"title"];//經過LYTableViewCellInfo 父類方法kvc獲取到
cell.detailTextLabel.text = [cellInfo getUserInfoValueForKey:@"rightValue"];//經過LYTableViewCellInfo 父類方法kvc獲取到
return cell;
}
複製代碼
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
LYTableViewSectionInfo *sectionInfo = _arrSections[indexPath.section];
LYTableViewCellInfo *cellInfo = [sectionInfo getCellAt:indexPath.row];
id target = cellInfo.actionTarget;
SEL selector = cellInfo.actionSel;
if (cellInfo.selectionStyle) {
if ([target respondsToSelector:selector]) {
[target performSelector:selector withObject:cellInfo withObject:indexPath];//建立cellInfo時,target傳遞並實現了SEL事件,這裏就會發送這個消息,從而實現cell的點擊事件
}
}
}
複製代碼
該類裏的數據來源就是MMTableViewSectionInfo和MMTableViewCellInfo,前面構建好了這兩,這裏直接就能用了。 看下最簡單的調用示例:
#pragma mark - Creat View
- (void)creatTableView{
_tableViewInfo = [[LYTableViewInfo alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
[self.view addSubview:[_tableViewInfo getTableView]];
//cell數據
LYTableViewCellInfo *noactionCell = [LYTableViewCellInfo normalCellForTitle:@"無點擊事件" rightValue:@"沒有"];
LYTableViewCellInfo *actionCell = [LYTableViewCellInfo normalCellForSel:@selector(actionCellClick) target:self title:@"有點擊事件" rightValue:@"" accessoryType:UITableViewCellAccessoryDisclosureIndicator];
//section數據
LYTableViewSectionInfo *sectionInfo = [LYTableViewSectionInfo sectionInfoDefaut];
//添加
[sectionInfo addCell:noactionCell];
[sectionInfo addCell:actionCell];
[_tableViewInfo addSection:sectionInfo];
//刷新
[[_tableViewInfo getTableView] reloadData];
}
#pragma mark - Event
- (void)actionCellClick{
NSLog(@"點擊了actionCell");
}
複製代碼
經過上面一段代碼實現以下:
以最簡單最基礎的案例介紹了微信的構建方式,此方式構建知足了組件的可複用性、可維護性、高效性。 這裏只是作最簡單介紹,你們可根據本身的業務需求對相應的方法作調整,作擴展。
倉庫裏兩個Demo,一個是最基礎的組件,一個是稍微完善的組件 github地址