背景:

在搭建APP静态TableView界面时,都是每个vc对应创建一个UITableView,然后实现UITableViewDataSource、UITableViewDelegate等方法,这样的开发方式有几大弊端:
1)效率不高,每个界面都得创建,实现协议。
2)cell的点击事件区分时需要一大堆的if/else。
3)界面元素变化时,维护起来非常蛋疼,需要修改好几个地方的if/else。
在分析完微信后,发现微信搭建静态TableView页面时,并不会出现上面几个问题,搭建非常easy,所以决定将学习到的思路分享出来大家一起交流学习。

分析过程中用到的工具:

1.一台越狱的5s
2. dumpdecrypted(砸壳)
3.class-dump(导出头文件)
4.IDA(反汇编)
5.cycript(调试)

逆向的基础知识就不概述了,本文章主要是对微信进行静态分析

一、找到关键类

1.MMTableViewInfo

通过观察多个静态页面的vc,发现vc里没有直接创建UITableView,而是通过MMTableViewInfo这个类创建的,MMTableViewInfo里有个_tableView成员变量,并实现了UITableViewDataSource、UITableViewDelegate,所以无误。下图是MMTableViewInfo头文件截图部分内容:

2.MMTableViewSectionInfo

通过观察,很容易看出MMTableViewInfo中的成员变量_arrSections是_tableView的数据源,调试打印其元素是MMTableViewSectionInfo对象。下图是MMTableViewSectionInfo头文件截图部分内容:

3.MMTableViewCellInfo

通过观察,猜测MMTableViewSectionInfo中的_arrCells应该是每个section中的cell数组,调试打印其元素是MMTableViewCellInfo对象。下图是MMTableViewCellInfo头文件截图部分内容:

二、通过反向推理,正向梳理逻辑

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的数据源

现在知道了三者的构成关系,接下来的重点就是去分析其内部是如何实现的了。

三、分析内部实现

接下来通过IDA反汇编工具,查看每个类具体实现的伪代码

1. MMTableViewCellInfo的实现

先看下伪代码(因封装的方法较多,这里只分析一个方法):

分析转化为oc代码是这样的,类名前缀我使用了LY,注意:demo里对基础的cellInfo做了一层封装。 第二个方法有SEL和target,这里是微信对cell的选中事件进行了处理,使用了target/action方式,所以监听cell的点击时不需要使用代理,使得每个cell有自己的action,即做到了解耦,又不用写一堆的if/else了。
微信对一些信息使用kvc进行存取,比如这里的title(textLabel)和rightValue(detailTextLabel),存取的方法在MMTableViewCellInfo的父类MMTableViewUserInfo里。

2. MMTableViewSectionInfo的实现

这个类的实现相对简单,现在只看cell是如何添加的。

///添加cell
- (void)addCell:(LYTableViewCellInfo *)cell{[_arrCells addObject:cell];
}
复制代码

3. MMTableViewInfo的实现

- (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地址

逆向微信-分析学习微信是如何快速构建静态TableView界面的相关推荐

  1. 拼图登陆拼图二维码验证_如何使用拼图快速轻松地构建静态网站

    拼图登陆拼图二维码验证 by Rick West 由里克·韦斯特(Rick West) 如何使用拼图快速轻松地构建静态网站 (How to use Jigsaw to quickly and easi ...

  2. 微信小程序wepy框架快速入门

    微信小程序wepy框架快速入门 微信小程序简介 微信小程序,简称小程序,英文名Mini Program,是一种不需要下载安装即可使用的应用,它实现了应用"触手可及"的梦想,用户扫一 ...

  3. 微信怎么自动加好友java_iOS逆向开发之微信自动添加好友功能

    这一次,小程演示怎么让一个APP自动地运行,从而代替手工的操作.同样以"微信"以例,实现在一个微信群里面,对所有的成员,自动地一个一个地发出添加好友的请求. 知识点还是之前介绍的东 ...

  4. 【企业微信怎么使用】如何快速做好企业微信客户数量增长?

    如何快速做好企业微信客户数量增长?今天又是一期干货分享,下面就教大家几种方式: 01批量导入客户联系电话,通过企业微信自动加人软件批量添加朋友微信,可以结合自主产品福利活动,如客户反馈等方式,大幅度提 ...

  5. 微信支付个人接口如何快速对接payjs(收银台模式)

    微信支付个人接口如何快速对接payjs(收银台模式) 近期在了解个人支付接口,希望能解决我在微信上支付的问题.找了很多平台对比再三,感觉payjs比较专业,其它多是模仿payjs的东西.同时支持支付宝 ...

  6. 微信小程序没有找到可以构建的NPM包,请确认需要参与构建的npm在miniprogramroot目录

    文章目录 前言 一.排查是否安装npm 二.如果没有安装 1.npm init 会提示不是内部命令 2.安装node环境 三.开始构建nmp 1.进入小程序根目录(app.js所在目录),打开cmd ...

  7. 封装微信微博QQ分享lib快速使用

    上次封装了分享图片资源的处理趁着有空 把分享功能进行了整合封装 ShareLib 集成微信微博QQ分享功能 1.接入工程 在主工程的build.gradle 中添加maven仓库地址 maven { ...

  8. 微信扫描二维码快速登录网站

    在近期的一个项目中用到了微信扫描注册.登录网站功能所以整理了下希望对读者有帮助. 首先,你需要有一个没有绑定微信.微信公众平台的邮箱注册成为微信开放平台开发者,在管理中心创建移动应用.或者网站应用获得 ...

  9. 思路+步骤+方法,三步教你如何快速构建用户画像?

    思路+步骤+方法,三步教你如何快速构建用户画像? 2016-10-07 超哥 互联网er的早读课 互联网er的早读课 数十万互联网从业者的共同关注! 作者:超哥.作者授权早读课发表,转载请联系作者. ...

  10. 如何支撑企业快速构建数字孪生体

    摘要:详解华为云IoTA服务如何助力IoT数据开发者快速实现IoT数据价值变现,带你动手实践完成一整套工业物联网方案的开发. 本文分享自华为云社区<[云驻共创]孪生?数字孪生?欢迎进入极客的世界 ...

最新文章

  1. Lync 2013部署(1)—AD准备
  2. 吃完晚饭干什么的好方法
  3. mybatis修改mysql变量_Java通过MyBatis框架对MySQL数据进行增删查改的基本方法
  4. GIS+=地理信息+容器技术(4)——Docker执行
  5. java 循环标记_深入浅析Java 循环中标签的作用
  6. 大前端时代,从前端小工到架构师的进阶锦囊!
  7. Android内存管理-SoftReference的使用
  8. python与冒泡排序
  9. Java语言中:switch语句经典习题
  10. 毕设-周报-20150520
  11. 计算机主机后面辐射大,电脑背面辐射最大吗
  12. Gitgub学习笔记(二)
  13. 华硕linux网卡驱动,华硕官网主板型号”P5BV-C”的Linux的网卡驱动加载
  14. 同伦延拓法中的几个数学常识
  15. 用ln命令链接文件 --- 一根绳子上的蚂蚱?
  16. fast无线网卡linux驱动,fast无线网卡驱动,详细教您fast无线网卡驱动
  17. 腾讯视频url获取方法
  18. 【python爬虫实战】批量下载网站视频
  19. 多态(Python入门三十二)
  20. 关于非IE浏览器下Flash上传控件HTTP ERROR 302

热门文章

  1. jquery刷新iframe页面的方法
  2. 转载:小心别让圆角成了你列表的帧数杀手
  3. jQuery表单插件ajaxForm,ajaxSubmit使用详解
  4. linux Apache2.4安装提示APR not found的解决办法
  5. GPIO驱动实例:操作LED开关
  6. IS技术:稳定压倒一切
  7. 如何使页面POSTBACK后,仍然显示原来的显示位置
  8. linux内核之设备驱动
  9. Mutex(互斥锁)
  10. Libevent源码分析-----日志和错误处理