AYAspect
引用
使用CocoaPods可以方便地引入AYAspect。在Podfile中添加AYAspect的依赖。
pod "AYAspect"
简介
在iOS开发中,经常需要引入数据统计、主题应用等。如果在每个ViewController中的viewDidLoad或viewWillAppear等方法进行配置,通常会非常繁琐,同时也不容易维护。
在我编写的过程中,遇到了一些困难,在查找资料时,发现了一些神奇的工具Aspects,但感觉在易用性上,AYAspect更好用一些。
AYAspect采用极简化的AOP设计,专注于AOP的核心目标,将概念缩减到极致,无需繁复的XML配置。AYAspect提供了两种类型的AOP拦截,可以实现非常强大的AOP功能。
全局拦截
AYAspect提供全局拦截实现。全局拦截实现只需调用一次,即可对全局所有对象进行拦截。
以下是代码示例:
//全局拦截[Teacher save]方法
[AYAspect interceptSelector:@(save) inClass:[Teacher class] withInterceptor:self];
//清除Teacher下所有拦截器
[AYAspect clearInterceptorsForClass:[Teacher class]];
//清除Teacher下save方法所有拦截器
[AYAspect clearInterceptsForSelector:@selector(save) inClass:[Teacher class]];
注意: [AYAspect interceptSelector:inClass:withInterceptor:]不要多次调用,只需调用一次,对全局所有
的对象都有效。
实例拦截
AYAspect可以实现对单个实例进行拦截,而对其他实例没有影响。
以下是代码示例:
//拦截一个已存在的实例aTeacher下的save方法
Teacher *aTeacher = [Teacher new];
[AYAspect interceptSelector:@selector(save) inInstance:aTeacher withInterceptor:self]
AYInterceptor
AYInterceptor是拦截器协议。拦截器必须实现该协议下的- (void)intercept:(NSInvocation *)invocation
方法。
NSInvocation封装了被拦截方法的详细信息,拦截器可以通过操作此实例来达到修改函数调用的目的。
NSInvocation使用
NSInvocation是Apple提供的一种消息调用
的方式,由于许多同学对NSInvocation的使用方法并不是非常了解,在此对这类的一些常用用法进行一些解释。
获取/设置参数
/*
以[Teacher -loginWithUserName:(NSString *)userName password:(NSString *)pwd为例
第0个参数是target,第1个参数是SEL,第2个参数才是userName,第3个参数是pwd
*/
__unsafe_unretained NSString *userName = nil;
__unsafe_unretained NSString *pwd = nil;
[invocation getArgument:&userName atIndex:2];
[invocation getArgument:&pwd atIndex:3];
//设置参数的值
NSString *newUserName = @"newUserName";
[invocation setArgument:&newUserName];
[invocation retainArguments];
目标target
/*
以[Teacher -loginWithUserName:(NSString *)userName password:(NSString *)pwd为例
target即执行-loginWithUserName:password:的对象
*/
id target = [invocation target];
获取/修改返回值
/*
以[Teacher -loginWithUserName:(NSString *)userName password:(NSString *)pwd为例
target即执行-loginWithUserName:password:的对象
*/
BOOL isSuccess;
[invocation getReturnValue:&isSuccess];
//修改返回值
BOOL newReturnValue = YES;
[invocation setReturnValue:&isSuccess];
执行被拦截的函数
[invocation invoke];
Category
在参考工具Aspect的实现时,发现其实现了一个非常方便的Category方法,因此我也将其整合到我的方案中,以便使用。
//拦截所有Teacher下面的save方法
[Teacher ay_interceptSelector:@selector(save) withInterceptor:AYInterceptorMake(^(NSInvocation *invocation) {
NSLog(@"执行save方法之前做一些事情");
[invocation invoke];
NSLog(@"执行save方法之后做一些事情");
})];
//拦截实例aTeacher下面的save方法
Teacher *aTeacher = [Teacher new];
[aTeacher ay_interceptSelector:@selector(save) withInterceptor:AYInterceptorMake(^(NSInvocation *invocation) {
NSLog(@"执行save方法之前做一些事情");
[invocation invoke];
NSLog(@"执行save方法之后做一些事情");
})];
License
AYAspect遵循MIT许可证。更多信息,请参阅LICENSE文件。