Aop切面编程

2018-05-27  本文已影响28人  一只长毛猫

1 什么是切面编程
2 KVO就是一个切面编程的例子
3 借鉴KVO切面编程,用自己的方法实现
4 代码实现

切面编程概念

这种在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。

KVO切面编程实例

原理:Apple使用了isa 混写(isa - swizzling)来实现。如图


OC基础-KVO

关于KVO详细内容请看我的另一篇文章https://www.jianshu.com/p/c98c995bda08

实现自己的Aop

先了解一下OC消息转发的大致原理。
1 动态添加 resolveInstanceMethod:
2 重定向 forwardingTargetForSelector:
3 方法签名后,调用forwardingTargetForSelector
第3步,灵活性是最大的,可以改变方法的参数内容,个数,方法名字,方法接收对象等。Aop切面编程就是用的第三个。

假设Person类,有一个实例方法sayHello(); 现在要求,每次调用sayHello()之前调用一段代码Before,sayHello之后调用一段代码after。
1 创建子类,避免代码入侵。
动态创建一个Person类的子类FWHook_Person ,改变person对象的isa指向FWHook_Person. 后面的步奏,都是针对FWHook_Person的
2 把sayHello的方法实现保存在 方法alias_sayHello中
3 替换sayHello方法实现为_objc_msgForward。使得person调用sayHello方法时,立即触发消息转发机制。
4 替换forwardInvocation:为FWHook_forwardInvocation。在这里我们实现,我们需要做的一些具体操作


Aop流程图

当[person sayHello]时,实际调用[person _objc_msgForward], 触发消息转发调用 forwardInvocation的替换方法FWHook_forwardInvocation,在FWHook_forwardInvocation中依次调用before、alias_sayHello、after.

代码实现

1 FWHookItem对block进行代码签名

@interface FWHookItem : NSObject

@property (nonatomic, weak) id object;
@property (nonatomic, assign) SEL selector;
@property (nonatomic, assign) FWHookOption option;
@property (nonatomic, strong) id block;
@property (nonatomic, strong) NSMethodSignature *blockSignature;

+(instancetype)itemWithObject:(id)object selector:(SEL)selector option:(FWHookOption)option block:(id)block;

/*
 方法调用
 */
-(void)invokeWithParams:(NSArray*)params;

@end

2 FWHookContainer保存FWHookItem

@interface FWHookContainer : NSObject

@property(nonatomic,readonly)NSMutableArray<FWHookItem*> *beforeArray;
@property(nonatomic,readonly)NSMutableArray<FWHookItem*> *insteadArray;
@property(nonatomic,readonly)NSMutableArray<FWHookItem*> *afterArray;

-(void)addHookItem:(FWHookItem*)item;

@end

3 获取selector参数

@interface NSInvocation (FWArguments)

- (NSArray *)getParams;

@end

4 使用

typedef void (^ParamsBlock)(NSArray *params);

@interface NSObject (FWHook)

/*
 selector : 需要监听的方法
 option : 决定 block 执行时机,在selector的之前,之后,替代。 
 block :执行的代码块 返回的params就是,selector中的参数
 */
-(void)hookSelector:(SEL)selector withOption:(FWHookOption)option usingBlock:(ParamsBlock)block;
+(void)hookSelector:(SEL)selector withOption:(FWHookOption)option usingBlock:(ParamsBlock)block;


@end

源码地址:https://github.com/FSilver/FWHook

上一篇下一篇

猜你喜欢

热点阅读