人生如梦,一尊还酹江月。
前言
移动端开发常态,忙一阵闲一阵。这不,又到了闲的阶段了,趁还有点闲的时间(产品悄悄对我说,今天下个项目原型通过了,下周开始加班)就赶紧整合之前用到的知识点,一是方便自己以后查阅,二是也方便有需要的iOSer。
Aspects 简介
Aspects是一个简洁高效的用于使iOS支持AOP面向切面编程的库,它可以帮助你在不改变一个类或类实例的代码的前提下,有效更改类的行为。
使用需求
- ARC
- 使用iOS 7+和OS X 10.7或更高版本测试方面。
使用场景
- 统一处理逻辑。
- 在不改变源码的情况下,插入代码(如无侵染更改第三方库代码,干一些坏坏的事情)
有些小伙伴一看这个库,发现最近更新也是3年前,担心库有问题。听一大牛说,这个库偏底层,只要Apple底层框架不变,那这个库就很稳定。
Aspects 使用
pod search AspectsV1.4.2
该库是轻量级的,接口简单,只有2个方法:
/*
* selector: 要hook的目标方法
* AspectOptions: 枚举
AspectPositionAfter //目标方法调用之后走block
AspectPositionInstead //替换目标方法
AspectPositionBefore //目标方法之前
AspectOptionAutomaticRemoval //只实现一次
block:结合后面的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上会发现有个AspectInfo
,看源码:
@protocol AspectInfo <NSObject>
//返回调用者实例
- (id)instance;
//方法签名信息
- (NSInvocation *)originalInvocation;
//原方法调用的参数
- (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];
实现效果,对所有ViewController的生命周期和button的点击事件进行统计。
由于时间问题,对源码不再详细的阐述,源码用的核心知识点有:
- 消息转发
- runtime
- 自旋锁 (OSSpinLockLock)
- block的底层结构
后记
目前只是简单的使用,以后有时间了就把源码解析补出来。
网友评论