AOP/iOS中如何实现AOP

什么是AOP

AOP:Aspect Oriented Programming,译为面向切面编程。

在不修改源代码的情况下,通过运行时给程序添加统一功能的技术。

我觉得其中有两层涵义:

  • 第一:不修改源代码,即尽可能的解耦。
  • 第二:添加统一的功能,即我们能实现的是添加统一的单一的功能,在某处使用AOP,我们只能实现一项单一的功能。如:日志记录。当然你可以添加多个AOP的模块到项目中,每一个实现不同功能,但是每一个功能必须是单一的。

主要功能:日志记录,性能统计等。

iOS中如何实现AOP

在iOS中实现AOP的核心技术是Runtime,使用RuntimeMethod Swizzling黑魔法,我们可以移花接木,在运行时将方法的具体实现添油加醋、偷梁换柱。

文章
Method Swizzling


Aspectsjrswizzle

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 的消息转发机制,会有一定的性能消耗。所有对于过于频繁的调用,不建议使用 AspectsAspects更适用于视图/控制器相关的等每秒调用不超过1000次的代码。

代码示例

在调试应用时,使用Aspects动态添加日志记录功能。

[UIViewController aspect_hookSelector:@selector(viewWillAppear:) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> aspectInfo) {
    NSLog(@"Appear:--> %@", NSStringFromClass([aspectInfo.instance class]));
} error:NULL];

通过这段代码,我们给UIViewControllerviewWillAppear:方法添加了一个钩子,每当在调用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不匹配的错误。

猜你喜欢

转载自blog.csdn.net/jichunw/article/details/80103785