AOP简介
AOP: Aspect Oriented Programming 面向切面编程。
面向切面编程(也叫面向方面):Aspect Oriented Programming(AOP),是目前软件开发中的一个热点。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
AOP是OOP的延续,是(Aspect Oriented Programming)的缩写,意思是面向切面(方面)编程。
主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等等。
主要的意图是:将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改 变这些行为的时候不影响业务逻辑的代码。
可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,AOP可以说也是这种目标的一种实现。
假设把应用程序想成一个立体结构的话,OOP的利刃是纵向切入系统,把系统划分为很多个模块(如:用户模块,文章模块等等),而AOP的利刃是横向切入系统,提取各个模块可能都要重复操作的部分(如:权限检查,日志记录等等)。由此可见,AOP是OOP的一个有效补充。
注意:AOP不是一种技术,实际上是编程思想。凡是符合AOP思想的技术,都可以看成是AOP的实现
iOS中面向切片编程一般有两种方式 ,一个是直接基于runtime 的method-Swizzling.还有一种就是基于NSProxy
下面记录一下基于NSProxy
的面相切片编程,先创建AOPProxy继承NSProxy:
.h
#import <Foundation/Foundation.h>
typedef void(^proxyBlock)(id target,SEL selector);
NS_ASSUME_NONNULL_BEGIN
@interface AOPProxy : NSProxy
+(instancetype)proxyWithTarget:(id)target;
-(void)inspectSelector:(SEL)selector preSelTask:(proxyBlock)preTask endSelTask:(proxyBlock)endTask;
@end
NS_ASSUME_NONNULL_END
.m
#import "AOPProxy.h"
@interface AOPProxy ()
@property(nonatomic,strong)id target;
@property(nonatomic,strong)NSMutableDictionary *preSelTaskDic;
@property(nonatomic,strong)NSMutableDictionary *endSelTaskDic;
@end
@implementation AOPProxy
-(NSMutableDictionary *)preSelTaskDic{
if (!_preSelTaskDic) {
_preSelTaskDic = [NSMutableDictionary dictionaryWithCapacity:1];
}
return _preSelTaskDic;
}
-(NSMutableDictionary *)endSelTaskDic{
if (!_endSelTaskDic) {
_endSelTaskDic = [NSMutableDictionary dictionaryWithCapacity:1];
}
return _endSelTaskDic;
}
-(instancetype)initWithTarget:(id)target{
self.target = target;
return self;
}
+(instancetype)proxyWithTarget:(id)target{
return [[self alloc] initWithTarget:target];
}
-(void)inspectSelector:(SEL)selector preSelTask:(proxyBlock)preTask endSelTask:(proxyBlock)endTask{
NSString *selKey = NSStringFromSelector(selector);
if (preTask) {
self.preSelTaskDic[selKey] = preTask;
}
if (endTask) {
self.endSelTaskDic[selKey] = endTask;
}
}
-(NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
return [self.target methodSignatureForSelector:sel];
}
-(void)forwardInvocation:(NSInvocation *)invocation{
NSString *selKey = NSStringFromSelector(invocation.selector);
proxyBlock pretask =self.preSelTaskDic[selKey];
proxyBlock endtask = self.endSelTaskDic[selKey];
if (pretask) {
pretask(self.target,invocation.selector);
}
[invocation invokeWithTarget:self.target];
if (endtask) {
endtask(self.target,invocation.selector);
}
}
@end
-(void)inspectSelector:(SEL)selector preSelTask:(proxyBlock)preTask endSelTask:(proxyBlock)endTask;
第一个参数是需要hook的方法名字 后面两个分别是hook 该方法后 执行前需要执行的block 和 执行后的需要执行的block.创建两个字典,分别存放 不同selector 对应的执行block(可能一个target有好几个方法需要被hook).
执行:
//AOP
-(void)inspect{
NSMutableArray *targtArray = [AOPProxy proxyWithTarget:[NSMutableArray arrayWithCapacity:1]];
[(AOPProxy *)targtArray inspectSelector:@selector(addObject:) preSelTask:^(id target, SEL selector) {
[target addObject:@"-------"];
NSLog(@"%@我加进来之前",target);
} endSelTask:^(id target, SEL selector) {
[target addObject:@"-------"];
NSLog(@"%@我加进来之后",target);
}];
[targtArray addObject:@"我是一个元素"];
}
打印:
2019-08-17 19:00:52.659840+0800 NSProxyStudy[10283:2864736] (
"-------"
)我加进来之前
2019-08-17 19:00:52.659924+0800 NSProxyStudy[10283:2864736] (
"-------",
"\U6211\U662f\U4e00\U4e2a\U5143\U7d20",
"-------"
)我加进来之后
网友评论