Aspects是一個簡潔高效的用于使iOS支持AOP面向切面編程的庫.它可以幫助你在不改變一個類或類實例的代碼的前提下,有效更改類的行為.
AOP (面向切面編程):
在軟件業(yè),AOP為Aspect Oriented Programming的縮寫,意為:面向切面編程,通過預編譯方式和運行期動態(tài)代理實現(xiàn)程序功能的統(tǒng)一維護的一種技術。
在以下場景中,用AOP技術可以節(jié)省很多的工作量:
1.用戶通過客戶端獲取服務器端數(shù)據(jù),做權限檢查。
2.用戶和市場交互,為用戶的操作提供相應地購買參考或相關商品。
3.需要做日志記錄的操作。
安裝:
使用Aspects的項目要求是在ARC環(huán)境下,系統(tǒng)要求是iOS 7或更高,和OS X 10.7 及更高版本。滿足環(huán)境要求后,就可以使用Cocopods進行安裝了。
在Podfile下添加:
pod 'AspectsV1.4.2', '~> 1.4.2’
然后,命令行執(zhí)行:
pod install --verbose —no-repo-update
執(zhí)行成功后,重新打開我們的項目目錄下.xcworkspace文件。
主要方法:
Aspects為NSObject類提供了如下的方法:
+ (id<AspectToken>)aspect_hookSelector:(SEL)selector
withOptions:(AspectOptions)options
usingBlock:(id)block
error:(NSError **)error;
- (id<AspectToken>)aspect_hookSelector:(SEL)selector
withOptions:(AspectOptions)options
usingBlock:(id)block
error:(NSError **)error;
這兩個方法,都可以用來修改原方法。
返回值是一個id<AspectToken>對象,可以用來注銷在方法中所做的修改:
id<AspectToken> aspect = ...;
[aspect remove];
參數(shù)里面,第一個selector用來設置需要添加功能的方法,options有如下選擇:
AspectPositionAfter = 0, ///在原方法調用完成以后進行調用
AspectPositionInstead = 1, ///取代原方法 AspectPositionBefore = 2, ///在原方法調用簽執(zhí)行
AspectOptionAutomaticRemoval = 1 << 3 ///在調用了一次后清除(只能在對象方法中使用)
block是用來寫功能模塊,參數(shù)可以為空,默認的第一個參數(shù)是id<AspectInfo>類型。AspectInfo協(xié)議有如下方法:
/// 對象調用時,放回對象
- (id)instance;
/// 方法的原始實現(xiàn)
- (NSInvocation *)originalInvocation;
/// 原方法調用的參數(shù)
- (NSArray *)arguments;
最后error用于返回一個錯誤的指針。
官方的一個實用例子:
[PSPDFDrawView aspect_hookSelector:@selector(shouldProcessTouches:withEvent:) withOptions:AspectPositionInstead usingBlock:^(id<AspectInfo> info, NSSet *touches, UIEvent *event) {
// Call original implementation.
BOOL processTouches;
NSInvocation *invocation = info.originalInvocation;
[invocation invoke];
[invocation getReturnValue:&processTouches];
if (processTouches) {
processTouches = pspdf_stylusShouldProcessTouches(touches, event);
[invocation setReturnValue:&processTouches];
}
} error:NULL];
使用:
我們創(chuàng)建好一個工程,用pods安裝好Aspects。
接著添加一個UIViewController的子類TwoViewController,從當前的ViewController點擊button可以present到TwoViewController,然后點擊TwoViewController又可以dismiss到ViewController;再給ViewController實現(xiàn)兩個touch方法,分別為點擊開始和點擊結束,用它們來改變ViewController的view屬性的一些可見的屬性,最后添加一個私有方法setupUISystem,也讓它完成一些改變view屬性的功能,在viewDidLoad調用。
好了,基本功能完成后,運行我們的工程,看是否按照預期執(zhí)行。
然后在AppDelegate的- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 生命周期方法中加入Aspects的代碼:
[UIViewController aspect_hookSelector:@selector(viewWillAppear:) withOptions:AspectPositionAfter usingBlock:^(){
NSLog(@"view appear! -->>>>>>>>>><<<<<<<<<<<<<--");
} error:nil];
[ViewController aspect_hookSelector:@selector(touchesBegan:withEvent:) withOptions:AspectPositionInstead usingBlock:^() {
NSLog(@"color orange!");
}error:nil];
[ViewController aspect_hookSelector:@selector(touchesEnded:withEvent:) withOptions:AspectPositionAfter usingBlock:^(){
NSLog(@"color purle");
} error:nil];
ViewController *vc = [[ViewController alloc] init];
[vc aspect_hookSelector:@selector(setupUISystem) withOptions:AspectPositionAfter|AspectOptionAutomaticRemoval usingBlock:^(){
NSLog(@"setupUISystem As");
} error:nil];
再運行,看看控制臺的是否有輸出,原工程的功能是否有所改變。
我們發(fā)現(xiàn):
1.在父類中的修改的方法,對子類都產(chǎn)生的作用。(1.4.2的特性)
2.Aspects的方法都按照預期執(zhí)行,修改了原功能。
3.私有方法也可以被修改。
其他:
Aspectes 會自動標記自己,所有很容易在調用棧中查看某個方法是否已經(jīng)調用:

最后附上一個統(tǒng)計功能的庫:https://github.com/orta/ARAnalytics
更多優(yōu)質文章請關注微信公眾號(iOS優(yōu)文)
