在搭建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
先看下伪代码(因封装的方法较多,这里只分析一个方法):
这个类的实现相对简单,如今只看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地址