逆向微信-分析學(xué)習(xí)微信是如何快速構(gòu)建靜態(tài)TableView界面的

example_home.png
背景:

在搭建APP靜態(tài)TableView界面時(shí)向臀,都是每個(gè)vc對(duì)應(yīng)創(chuàng)建一個(gè)UITableView摇邦,然后實(shí)現(xiàn)UITableViewDataSource、UITableViewDelegate等方法常侦,這樣的開(kāi)發(fā)方式有幾大弊端:
1)效率不高星爪,每個(gè)界面都得創(chuàng)建,實(shí)現(xiàn)協(xié)議。
2)cell的點(diǎn)擊事件區(qū)分時(shí)需要一大堆的if/else
3)界面元素變化時(shí)蟆盐,維護(hù)起來(lái)非常蛋疼承边,需要修改好幾個(gè)地方的if/else
在分析完微信后,發(fā)現(xiàn)微信搭建靜態(tài)TableView頁(yè)面時(shí)石挂,并不會(huì)出現(xiàn)上面幾個(gè)問(wèn)題博助,搭建非常easy,所以決定將學(xué)習(xí)到的思路分享出來(lái)大家一起交流學(xué)習(xí)痹愚。

分析過(guò)程中用到的工具:

1.一臺(tái)越獄的5s
2. dumpdecrypted(砸殼)
3.class-dump(導(dǎo)出頭文件)
4.IDA(反匯編)
5.cycript(調(diào)試)

逆向的基礎(chǔ)知識(shí)就不概述了富岳,本文章主要是對(duì)微信進(jìn)行靜態(tài)分析

一、找到關(guān)鍵類(lèi)

1.MMTableViewInfo

通過(guò)觀察多個(gè)靜態(tài)頁(yè)面的vc拯腮,發(fā)現(xiàn)vc里沒(méi)有直接創(chuàng)建UITableView窖式,而是通過(guò)MMTableViewInfo這個(gè)類(lèi)創(chuàng)建的,MMTableViewInfo里有個(gè)_tableView成員變量动壤,并實(shí)現(xiàn)了UITableViewDataSource萝喘、UITableViewDelegate,所以無(wú)誤琼懊。下圖是MMTableViewInfo頭文件截圖部分內(nèi)容:
MMTableViewInfo.png
2.MMTableViewSectionInfo

通過(guò)觀察阁簸,很容易看出MMTableViewInfo中的成員變量_arrSections是_tableView的數(shù)據(jù)源,調(diào)試打印其元素是MMTableViewSectionInfo對(duì)象哼丈。下圖是MMTableViewSectionInfo頭文件截圖部分內(nèi)容:
MMTableViewSectionInfo.png
3.MMTableViewCellInfo

通過(guò)觀察启妹,猜測(cè)MMTableViewSectionInfo中的_arrCells應(yīng)該是每個(gè)section中的cell數(shù)組,調(diào)試打印其元素是MMTableViewCellInfo對(duì)象醉旦。下圖是MMTableViewCellInfo頭文件截圖部分內(nèi)容:
MMTableViewCellInfo.png

二饶米、通過(guò)反向推理,正向梳理邏輯

1.觀察MMTableViewCellInfo頭文件车胡,通過(guò)fCellHeight檬输、cellStyle、accessoryType匈棘、+ (id)normalCellForTitle:(id)arg1 rightValue:(id)arg2這幾個(gè)屬性和方法褪猛,應(yīng)該可以想到,這個(gè)類(lèi)就是為cell準(zhǔn)備數(shù)據(jù)的羹饰。

2.觀察MMTableViewSectionInfo頭文件伊滋,- (void)addCell:(id)arg1;通過(guò)該方法添加cellInfo到_arrCells里構(gòu)成了一個(gè)組的數(shù)據(jù)

3.觀察MMTableViewInfo頭文件,- (void)addSection:(id)arg1队秩,可以想到是添加sectionInfo到_arrSections里構(gòu)成了UITableView的數(shù)據(jù)源

現(xiàn)在知道了三者的構(gòu)成關(guān)系笑旺,接下來(lái)的重點(diǎn)就是去分析其內(nèi)部是如何實(shí)現(xiàn)的了。

三馍资、分析內(nèi)部實(shí)現(xiàn)

接下來(lái)通過(guò)IDA反匯編工具筒主,查看每個(gè)類(lèi)具體實(shí)現(xiàn)的偽代碼

1. MMTableViewCellInfo的實(shí)現(xiàn)

先看下偽代碼(因封裝的方法較多,這里只分析一個(gè)方法):


MMTableViewCellInfo normalcell.png

分析轉(zhuǎn)化為oc代碼是這樣的,類(lèi)名前綴我使用了LY乌妙,注意:demo里對(duì)基礎(chǔ)的cellInfo做了一層封裝使兔。


LYTableViewCellInfo.png

第二個(gè)方法有SEL和target,這里是微信對(duì)cell的選中事件進(jìn)行了處理藤韵,使用了target/action方式虐沥,所以監(jiān)聽(tīng)cell的點(diǎn)擊時(shí)不需要使用代理,使得每個(gè)cell有自己的action泽艘,即做到了解耦欲险,又不用寫(xiě)一堆的if/else了。
微信對(duì)一些信息使用kvc進(jìn)行存取匹涮,比如這里的title(textLabel)和rightValue(detailTextLabel)天试,存取的方法在MMTableViewCellInfo的父類(lèi)MMTableViewUserInfo里。
2. MMTableViewSectionInfo的實(shí)現(xiàn)

這個(gè)類(lèi)的實(shí)現(xiàn)相對(duì)簡(jiǎn)單然低,現(xiàn)在只看cell是如何添加的喜每。

///添加cell
- (void)addCell:(LYTableViewCellInfo *)cell{
    [_arrCells addObject:cell];
}
3. MMTableViewInfo的實(shí)現(xiàn)
- (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"];//通過(guò)LYTableViewCellInfo 父類(lèi)方法kvc獲取到
    cell.detailTextLabel.text = [cellInfo getUserInfoValueForKey:@"rightValue"];//通過(guò)LYTableViewCellInfo 父類(lèi)方法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];//創(chuàng)建cellInfo時(shí),target傳遞并實(shí)現(xiàn)了SEL事件雳攘,這里就會(huì)發(fā)送這個(gè)消息灼卢,從而實(shí)現(xiàn)cell的點(diǎn)擊事件
        }
    }
}

該類(lèi)里的數(shù)據(jù)來(lái)源就是MMTableViewSectionInfo和MMTableViewCellInfo,前面構(gòu)建好了這兩来农,這里直接就能用了。
看下最簡(jiǎn)單的調(diào)用示例:

#pragma mark - Creat View
- (void)creatTableView{
    _tableViewInfo = [[LYTableViewInfo alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
    [self.view addSubview:[_tableViewInfo getTableView]];
    
    //cell數(shù)據(jù)
    LYTableViewCellInfo *noactionCell = [LYTableViewCellInfo normalCellForTitle:@"無(wú)點(diǎn)擊事件" rightValue:@"沒(méi)有"];
    LYTableViewCellInfo *actionCell = [LYTableViewCellInfo normalCellForSel:@selector(actionCellClick) target:self title:@"有點(diǎn)擊事件" rightValue:@"" accessoryType:UITableViewCellAccessoryDisclosureIndicator];
    
    //section數(shù)據(jù)
    LYTableViewSectionInfo *sectionInfo = [LYTableViewSectionInfo sectionInfoDefaut];

    //添加
    [sectionInfo addCell:noactionCell];
    [sectionInfo addCell:actionCell];
    [_tableViewInfo addSection:sectionInfo];
    
    //刷新
    [[_tableViewInfo getTableView] reloadData];
}

#pragma mark - Event
- (void)actionCellClick{
    NSLog(@"點(diǎn)擊了actionCell");
}

通過(guò)上面一段代碼實(shí)現(xiàn)如下:


baseExample.png

總結(jié):

以最簡(jiǎn)單最基礎(chǔ)的案例介紹了微信的構(gòu)建方式崇堰,此方式構(gòu)建滿(mǎn)足了組件的可復(fù)用性沃于、可維護(hù)性、高效性海诲。
這里只是做最簡(jiǎn)單介紹繁莹,大家可根據(jù)自己的業(yè)務(wù)需求對(duì)相應(yīng)的方法做調(diào)整,做擴(kuò)展特幔。

倉(cāng)庫(kù)里兩個(gè)Demo咨演,一個(gè)是最基礎(chǔ)的組件,一個(gè)是稍微完善的組件
github:https://github.com/dev-liyang/LYTableViewWidget

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蚯斯,一起剝皮案震驚了整個(gè)濱河市薄风,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌拍嵌,老刑警劉巖遭赂,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異横辆,居然都是意外死亡撇他,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)困肩,“玉大人划纽,你說(shuō)我怎么就攤上這事⌒炕” “怎么了勇劣?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)蹋绽。 經(jīng)常有香客問(wèn)我芭毙,道長(zhǎng),這世上最難降的妖魔是什么卸耘? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任退敦,我火速辦了婚禮,結(jié)果婚禮上蚣抗,老公的妹妹穿的比我還像新娘侈百。我一直安慰自己,他們只是感情好翰铡,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布钝域。 她就那樣靜靜地躺著,像睡著了一般锭魔。 火紅的嫁衣襯著肌膚如雪例证。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,754評(píng)論 1 307
  • 那天迷捧,我揣著相機(jī)與錄音织咧,去河邊找鬼。 笑死漠秋,一個(gè)胖子當(dāng)著我的面吹牛笙蒙,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播庆锦,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼捅位,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了搂抒?” 一聲冷哼從身側(cè)響起艇搀,我...
    開(kāi)封第一講書(shū)人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎求晶,沒(méi)想到半個(gè)月后中符,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡誉帅,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年淀散,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了右莱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡档插,死狀恐怖慢蜓,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情郭膛,我是刑警寧澤晨抡,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站则剃,受9級(jí)特大地震影響耘柱,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜棍现,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一调煎、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧己肮,春花似錦士袄、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至艘绍,卻和暖如春赤拒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背诱鞠。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工挎挖, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人般甲。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像鹅颊,于是被迫代替她去往敵國(guó)和親敷存。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1堪伍、通過(guò)CocoaPods安裝項(xiàng)目名稱(chēng)項(xiàng)目信息 AFNetworking網(wǎng)絡(luò)請(qǐng)求組件 FMDB本地?cái)?shù)據(jù)庫(kù)組件 SD...
    陽(yáng)明先生_X自主閱讀 15,982評(píng)論 3 119
  • 一:駝背凸腰 駝背凸腰是當(dāng)前很常見(jiàn)的不良身體姿態(tài)現(xiàn)象锚烦,特別是在青少年當(dāng)中,其中帝雇,極少數(shù)是由于先天遺傳的缺陷涮俄,大部分...
    駱長(zhǎng)珊閱讀 1,324評(píng)論 0 1
  • 早上上班,拎著豆?jié){雞蛋坐上出租車(chē)尸闸,馬上放下豆?jié){彻亲,系上安全帶孕锄!突然,豆?jié){倒在車(chē)上了苞尝,弄得車(chē)上到處都是畸肆。 首先我的內(nèi)心...
    上善若水澤萬(wàn)物閱讀 115評(píng)論 2 6
  • 文/李立文 不知道 什么時(shí)侯 丟掉了鄉(xiāng)愁 是因?yàn)?那里 沒(méi)了 父親的烤白薯 沒(méi)了 父親的玉米香 沒(méi)了 父親踏山的腳...
    啟明星子閱讀 249評(píng)論 0 0
  • 運(yùn)用工具是為了更快更好的解決問(wèn)題,可太依賴(lài)一個(gè)工具宙址,有時(shí)卻容易陷進(jìn)去轴脐,反而成了解決問(wèn)題的障礙。 上周五抡砂,處理一個(gè)E...
    魚(yú)兒圓滾滾閱讀 618評(píng)論 0 0