什么是AOP
AOP:Aspect Oriented Programming,译为面向切面编程。
在不修改源代码的情况下,通过运行时给程序添加统一功能的技术。
我觉得其中有两层涵义:
- 第一:不修改源代码,即尽可能的解耦。
- 第二:添加统一的功能,即我们能实现的是添加统一的单一的功能,在某处使用AOP,我们只能实现一项单一的功能。如:日志记录。当然你可以添加多个AOP的模块到项目中,每一个实现不同功能,但是每一个功能必须是单一的。
主要功能:日志记录,性能统计等。
iOS中如何实现AOP
在iOS中实现AOP的核心技术是Runtime
,使用Runtime
的Method Swizzling
黑魔法,我们可以移花接木,在运行时将方法的具体实现添油加醋、偷梁换柱。
AOP技术实现
Aspects
+ (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;
实际为同一个方法,这两个方法是同名不同类型的方法,一个是静态类方法,一个是成员方法。
使用这个方法可以给类的实例方法添加一个Block
,并且对这个类的所有对象都会起作用。
所有的调用,都会是线程安全的。Aspects
使用了Objective-C
的消息转发机制,会有一定的性能消耗。所有对于过于频繁的调用,不建议使用 Aspects
。Aspects
更适用于视图/控制器相关的等每秒调用不超过1000次的代码。
代码示例
在调试应用时,使用Aspects
动态添加日志记录功能。
[UIViewController aspect_hookSelector:@selector(viewWillAppear:) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> aspectInfo) {
NSLog(@"Appear:--> %@", NSStringFromClass([aspectInfo.instance class]));
} error:NULL];
通过这段代码,我们给UIViewController
的viewWillAppear:
方法添加了一个钩子,每当在调用viewWillAppear:
后就会执行block中的代码。在此我们打印了一段Log,通过log我们可以看到当前显示的页面的VC名称,从而快速定位到该类。还可以在ViewController的Dealloc时打印log:
[UIViewController aspect_hookSelector:NSSelectorFromString(@"dealloc") withOptions:AspectPositionBefore usingBlock:^(id<AspectInfo> aspectInfo) {
NSLog(@"Dealloc:---->: %@", NSStringFromClass([aspectInfo.instance class]));
} error:NULL];
与上一段代码的微小差别是Selector
换成了NSSelectorFromString(@"dealloc")
,而不是@selector(dealloc)
,这是因为在ARC下面是不能直接手动调用Dealloc
的,@selector(dealloc)
会被编译器直接报错。
通过这个log,我们可以知道ViewController
是否释放,如果没有释放很可能就是有循环引用,这时你务必仔细检查你的代码,这在性能调试和debug中非常有用。
Aspects的坑
- 无法为类方法添加
hooking
block
无法自动判断参数个数,自动匹配。如果你添加一个无参的方法,而block
中有跟一个参数,那么你会收到block
不匹配的错误。