浅谈Objc之AOP编程

xiaoxiao2021-02-28  39

AOP编程,就是切片编程,是切入到函数实现(函数代码块实现)的编程。问题场景:当你想在某个已存在函数代码块实现之前或之后,添加另一部分额外功能时,但又不想直接将代码插入(这部分代码相对独立,插进去总觉得和原来代码是逻辑无关的),也不想通过父类统一添加(有可能创建多个父类?);看样子,在编译阶段解决此问题,有些难度;在运行阶段有办法吗?有,就是AOP。 既然说的是OC中的AOP,就直说OC中如何实现的。 先说下原理:在OC中,不管类方法还是实例方法,”方法声明“用的是选择器类型记录的,即SEL类型,通常叫选择器名;方法都有自己的实现,像在c或c++中,方法名指向的就是函数入口(函数实现入口),OC不是这样的,他是通过选择器名索引到对应的实现,然后执行实现代码。 回到问题场景,如果我们能改变选择器名对应的实现地址,让他对应你那那段独立的代码实现,然后定义另外一个选择器名,让他对应原来那段代码实现,这样,程序运行时,就在不改变源代码的基础上完成了额外工作。需要注意的是,由于我们自己定义了新的选择器名,让他对应原来那段代码实现,所以在执行完额外功能后,需要在独立的代码实现后发送新的选择器消息。

项目中,拥有这中需求的类应该不止一个,所以我将交换函数实现的功能,放在NSObject分类中。这样哪个类需要,就在自己分类中的类方法发load中实现即可。下面举了UIViewController和UIControl俩个类的交换函数实现。

// // NSObject+AOP.h // #import <Foundation/Foundation.h> @interface NSObject (AOP) /** 交换方法名对应的实现 @param newSelector 新方法名 @param oldSelector 老方法名 */ +(void)exChangeMethodImpWithNewSelctor:(SEL)newSelector oldSelctor:(SEL)oldSelector; @end // // NSObject+AOP.m // #import "NSObject+AOP.h" #import <objc/runtime.h> @implementation NSObject (AOP) /** 交换方法名对应的实现(这样所有的NSObject子类都可以调用,谁调用self就是谁) @param newSelector 新选择器方法名 @param oldSelector 老选择器方法名 */ +(void)exChangeMethodImpWithNewSelctor:(SEL)newSelector oldSelctor:(SEL)oldSelector{ Method newMethod = class_getInstanceMethod([self class], newSelector); Method oldMethod = class_getInstanceMethod([self class], oldSelector); method_exchangeImplementations(newMethod, oldMethod); } @end // // UIViewController+AOP.h // #import <UIKit/UIKit.h> @interface UIViewController (AOP) @end // // UIViewController+AOP.m // #import "UIViewController+AOP.h" #import "NSObject+AOP.h" @implementation UIViewController (AOP) //系统在加载类的时候,会自动调用load方法,且只调用一次。所以,在这里做aop操作。 +(void)load{ SEL newSelector = @selector(aop_viewWillAppear:); SEL oldSelector = @selector(viewWillAppear:); [self exChangeMethodImpWithNewSelctor:newSelector oldSelctor:oldSelector]; } -(void)aop_viewWillAppear:(BOOL)animated{ NSLog(@"替换后是%s", __func__); //调用原来实现 [self aop_viewWillAppear:animated]; } @end // // UIControl+AOP.h // #import <UIKit/UIKit.h> @interface UIControl (AOP) @end // // UIControl+AOP.m // #import "UIControl+AOP.h" #import "NSObject+AOP.h" @implementation UIControl (AOP) //系统在加载类的时候,会自动调用load方法,且只调用一次。所以,在这里最aop操作。 +(void)load{ SEL newSelector = @selector(aop_sendAction:to:forEvent:); SEL oldSelector = @selector(sendAction:to:forEvent:); [self exChangeMethodImpWithNewSelctor:newSelector oldSelctor:oldSelector]; } - (void)aop_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event{ NSLog(@"替换后是%s", __func__); //调用原来实现 [self aop_sendAction:action to:target forEvent:event]; } @end
转载请注明原文地址: https://www.6miu.com/read-2613232.html

最新回复(0)