在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,是函数式编程的一种衍生范型。通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等等。主要的意图是:将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。
这里举个例子,我们有个方法sumA:andB:, 用来返回ab之和的一个字串,我们在这个方法前和方法后都增加个一段代码
- (void)clickTestAop:(id)sender { AopTestM *test = [[AopTestM alloc] init]; NSLog(@"run1"); [test sumA:1 andB:2]; NSString *before = [XYAOP interceptClass:[AopTestM class] beforeExecutingSelector:@selector(sumA:andB:) usingBlock:^(NSInvocation *invocation) { int a = 3; int b = 4; [invocation setArgument:&a atIndex:2]; [invocation setArgument:&b atIndex:3]; NSLog(@"berore fun. a = %d, b = %d", a , b); }]; NSString *after = [XYAOP interceptClass:[AopTestM class] afterExecutingSelector:@selector(sumA:andB:) usingBlock:^(NSInvocation *invocation) { int a; int b; NSString *str; [invocation getArgument:&a atIndex:2]; [invocation getArgument:&b atIndex:3]; [invocation getReturnValue:&str]; NSLog(@"after fun. a = %d, b = %d, sum = %@", a , b, str); }]; NSLog(@"run2"); [test sumA:1 andB:2]; [XYAOP removeInterceptorWithIdentifier:before]; [XYAOP removeInterceptorWithIdentifier:after]; NSLog(@"run3"); [test sumA:1 andB:2]; } - (NSString *)sumA:(int)a andB:(int)b { int value = a + b; NSString *str = [NSString stringWithFormat:@"fun running. sum : %d", value]; NSLog(@"%@", str); return str; }
我们执行这段代码的时候,大伙猜猜结果是啥.结果如下
2014-10-28 22:52:47.215 JoinShow[3751:79389] run1 2014-10-28 22:52:52.744 JoinShow[3751:79389] fun running. sum : 3 2014-10-28 22:52:52.745 JoinShow[3751:79389] run2 2014-10-28 22:52:52.745 JoinShow[3751:79389] berore fun. a = 3, b = 4 2014-10-28 22:52:52.745 JoinShow[3751:79389] fun running. sum : 7 2014-10-28 22:52:52.745 JoinShow[3751:79389] after fun. a = 3, b = 4, sum = fun running. sum : 7 2014-10-28 22:52:52.746 JoinShow[3751:79389] run3 2014-10-28 22:52:52.746 JoinShow[3751:79389] fun running. sum : 3
用Objective-C强大的runtime.
我们知道当给一个对象发送一个方法的时候, 如果当前类和父类都没实现该方法的时候就会走转发流程
迷茫的同学请搜 "Objective-C 消息转发".
了解了消息转发,那么我们aop的思路就来了,我们是先干掉原本的方法funa,这样当给对象发送方法的时候就会走转发流程,我们再hook了对象的快速消息转发方法,把实现funa的对象指成我们的aop对象, 最后在aop对象的标准消息转发里执行before instead after方法.
具体的代码欢迎大伙去github下载, 记得给咱点个star
link https://github.com/uxyheaven/XYQuickDevelop
在代码里搜 XYAOP.h
介绍一些用到的runtime方法
// 给 cls 添加一个新方法 BOOL class_addMethod ( Class cls, SEL name, IMP imp, const char *types ); // 替换 cls 里的一个方法的实现 IMP class_replaceMethod ( Class cls, SEL name, IMP imp, const char *types ); // 返回 cls 的指定方法 Method class_getInstanceMethod ( Class cls, SEL name ); // 设置一个方法的实现 IMP method_setImplementation ( Method m, IMP imp ); // 返回 cls 里的 name 方法的实现 IMP class_getMethodImplementation ( Class cls, SEL name );