人生如夢,一樽還酹江月。
前言
移動端開發(fā)常態(tài),忙一陣閑一陣。這不,又到了閑的階段了,趁還有點閑的時間(產(chǎn)品悄悄對我說,今天下個項目原型通過了,下周開始加班)就趕緊整合之前用到的知識點,一是方便自己以后查閱,二是也方便有需要的iOSer。
Aspects 簡介
Aspects是一個簡潔高效的用于使iOS支持AOP面向切面編程的庫,它可以幫助你在不改變一個類或類實例的代碼的前提下,有效更改類的行為。
使用需求
- ARC
- 使用iOS 7+和OS X 10.7或更高版本測試方面。
使用場景
- 統(tǒng)一處理邏輯。
- 在不改變源碼的情況下,插入代碼(如無侵染更改第三方庫代碼,干一些壞壞的事情)
有些小伙伴一看這個庫,發(fā)現(xiàn)最近更新也是3年前,擔(dān)心庫有問題。聽一大牛說,這個庫偏底層,只要Apple底層框架不變,那這個庫就很穩(wěn)定。
Aspects 使用
pod search AspectsV1.4.2
該庫是輕量級的,接口簡單,只有2個方法:
/*
* selector: 要hook的目標(biāo)方法
* AspectOptions: 枚舉
AspectPositionAfter //目標(biāo)方法調(diào)用之后走block
AspectPositionInstead //替換目標(biāo)方法
AspectPositionBefore //目標(biāo)方法之前
AspectOptionAutomaticRemoval //只實現(xiàn)一次
block:結(jié)合后面的demo看
error:拋出錯誤
*
*
*
*/
+ (id<AspectToken>)aspect_hookSelector:(SEL)selector
withOptions:(AspectOptions)options
usingBlock:(id)block
error:(NSError **)error;
/// Adds a block of code before/instead/after the current `selector` for a specific instance.
- (id<AspectToken>)aspect_hookSelector:(SEL)selector
withOptions:(AspectOptions)options
usingBlock:(id)block
error:(NSError **)error;
注意:上面2個方法只能hook實例(-)方法,對類(+)方法無效
官方demo
[UIViewController aspect_hookSelector:@selector(viewWillAppear:) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> aspectInfo, BOOL animated) {
NSLog(@"View Controller %@ will appear animated: %tu", aspectInfo.instance, animated);
} error:NULL];
demo上會發(fā)現(xiàn)有個AspectInfo,看源碼:
@protocol AspectInfo <NSObject>
//返回調(diào)用者實例
- (id)instance;
//方法簽名信息
- (NSInvocation *)originalInvocation;
//原方法調(diào)用的參數(shù)
- (NSArray *)arguments;
@end
目前用到:在appDelegate中
// 勾取 UIViewController 類所有實例的viewWillAppear: 方法
[UIViewController aspect_hookSelector:@selector(viewWillAppear:) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> info){
UIViewController *tempVC = (UIViewController *)info.instance;
NSLog(@">>>%@ viewWillAppear",[tempVC class]);
} error:nil];
[UIControl aspect_hookSelector:@selector(sendAction:to:forEvent:) withOptions:AspectPositionBefore usingBlock:^(id<AspectInfo> info){
UIControl *control = (UIControl *)info.instance;
if ([control isKindOfClass:[UIButton class]]) {
UIButton *btn = (UIButton *)control;
NSLog(@">>>%@",btn.titleLabel.text);
}
} error:nil];
實現(xiàn)效果,對所有ViewController的生命周期和button的點擊事件進行統(tǒng)計。
由于時間問題,對源碼不再詳細的闡述,源碼用的核心知識點有:
- 消息轉(zhuǎn)發(fā)
- runtime
- 自旋鎖 (OSSpinLockLock)
- block的底層結(jié)構(gòu)
后記
目前只是簡單的使用,以后有時間了就把源碼解析補出來。