Aspects簡(jiǎn)介:
Aspects github地址:https://github.com/steipete/Aspects.git
通過(guò)這兩個(gè)函數(shù)可以很好得對(duì)某一個(gè)類的所有實(shí)例和某一個(gè)實(shí)例的對(duì)應(yīng)方法進(jìn)行攔截。一個(gè)很好的使用場(chǎng)景无埃,公司產(chǎn)品要求盐类,要對(duì)用戶的頁(yè)面軌跡進(jìn)行統(tǒng)計(jì)驹针,也即用戶每次進(jìn)入到一個(gè)控制器調(diào)用viewWillAppear函數(shù)時(shí)進(jìn)行相應(yīng)的處理山害,現(xiàn)在有以下處理方式。
1惊暴、在每一個(gè)自定義的控制器的viewWillAppear函數(shù)添加處理代碼
2、自定義一個(gè)集成于UIViewController的基類趁桃,在viewWillAppear添加處理代碼辽话,然后只有所有的需要統(tǒng)計(jì)的控制器都繼承自這個(gè)基類控制器。
3卫病、使用Aspects來(lái)勾取UIViewController類的viewWillAppear方法油啤,在勾取的函數(shù)里添加代碼
其中方式1代碼重復(fù)太多,需要修改的地方較多蟀苛,不易維護(hù)益咬,方式2由于要所有的類都繼承自自定義基類,需要額外的溝通成本帜平,不可取幽告,方式三可以使用自定義類并重寫+ load方法來(lái)實(shí)現(xiàn)功能梅鹦,所有以前寫的代碼不用修改一行,只需繼承自UIViewController就可實(shí)現(xiàn)功能冗锁,這種思想有個(gè)專業(yè)術(shù)語(yǔ)叫AOP齐唆,即面向切片編程。
網(wǎng)絡(luò)上對(duì)于Aspects和method swizzing使用的帖子很多冻河,基本用法我也無(wú)需贅述箍邮,在使用這個(gè)庫(kù)和method swizzing時(shí)我都遇到一個(gè)問(wèn)題:如何實(shí)現(xiàn)對(duì)一個(gè)類的類方法(常說(shuō)的+方法)進(jìn)行替換?之前我以為使用Aspects無(wú)法實(shí)現(xiàn)這個(gè)功能芋绸,因?yàn)楫吘菇涌谥皇菍?shí)現(xiàn)了對(duì)-方法和某一對(duì)象的-方法進(jìn)行攔截媒殉。
于是我開始自己封裝了一個(gè)基于method swizzing的庫(kù)文件,利用運(yùn)行時(shí)的知識(shí)來(lái)對(duì)類的類方法來(lái)進(jìn)行替換摔敛,demo的地址:https://github.com/2446886848/ZHMethodSwizzingDemo.git實(shí)現(xiàn)起來(lái)效果還不錯(cuò)廷蓉,但是畢竟Aspects是經(jīng)過(guò)眾多開發(fā)者考驗(yàn)的一個(gè)方式,而且作者考慮的全面性和穩(wěn)定性也必然會(huì)高很多马昙。于是我開始試著實(shí)現(xiàn)使用Aspects桃犬,配合少許的代碼來(lái)實(shí)現(xiàn)對(duì)類方法的替換。
思路:無(wú)論是類的實(shí)例對(duì)象也好行楞,類對(duì)象也好攒暇,從運(yùn)行時(shí)的角度來(lái)說(shuō)都是對(duì)象,只不過(guò)他們?cè)谑褂玫倪^(guò)程中被人們區(qū)別化了罷了子房。既然類對(duì)象也是對(duì)象形用,它的方法存在于metal類(元類)中,那么對(duì)于metal類來(lái)說(shuō)证杭,類對(duì)象也只是單純的對(duì)象田度,只要我像對(duì)普通的實(shí)例方法那樣來(lái)處理類對(duì)象,那么實(shí)現(xiàn)替換類的方法也是可行的解愤。
廢話不多說(shuō)镇饺,拿代碼說(shuō)話!
首先導(dǎo)入Aspects框架到工程送讲,可以使用cocoapod也可用直接拖源代碼的方式導(dǎo)入奸笤。
因?yàn)橐褂眠\(yùn)行時(shí)的東西,接著導(dǎo)入運(yùn)行時(shí)頭文件#import?
自定義一個(gè)類哼鬓,類名為“Cat”监右,類中聲明了一個(gè)類方法+ (void)classFee;
實(shí)現(xiàn)+ (void)classFee
{
NSLog(@"Cat classFee");
}
然后開始使用Aspects框架了,代碼如下:
Class catMetal = objc_getMetaClass(NSStringFromClass(Cat.class).UTF8String);
[catMetal aspect_hookSelector:@selector(classFee) withOptions:AspectPositionAfter usingBlock:^(idaspectInfo){
NSLog(@"aspectFee");
} error:NULL];
接著在函數(shù)里面直接調(diào)用[Cat classFee]運(yùn)行程序异希,可在輸出控制臺(tái)看到輸出結(jié)果
至此秸侣,即可實(shí)現(xiàn)使用Aspects實(shí)現(xiàn)類方法攔截。