AOP: 面向切面编程,偏向于处理业务的某个阶段

适用场景:

  1. 参数校验:网络请求前的参数校验,返回数据的格式校验等等

  2. 无痕埋点:统一处理埋点,降低代码耦合度

  3. 页面统计:帮助统计页面访问量

  4. 事务处理:拦截指定事件,添加触发事件

  5. 异常处理:发生异常时使用面向切面的方式进行处理

  6. 热修复:AOP可以让我们在某方法执行前后或者直接替换为另一段代码,我们可以根据这个思路,实现bug修复

  我们希望将以上需求分离到非业务逻辑的方法中,尽可能的不影响业务逻辑的代码。

demo 从配置AOP到实际应用,有空给咱点个star~

源码分析

  0. 类说明

 MDAspectInfo:作为对象,包含调用信息(NSInvocation)的对象
         作为协议,提供访问对象的属性
 MDAspectIdentifier:包含一个hook的信息,调用者,时机,回调处理等
 MDAspectTracker:防止重复hook
 MDAspectsContainer:通过runtime给被hook的对象添加属性,提供存储和移除hook的方法
 MDAspectToken:提供移除hook的协议

  1. hook时机

typedef NS_OPTIONS(NSUInteger, MDAspectOptions) {
MDAspectPositionAfter = , /// 默认,当原方法执行完调用
MDAspectPositionInstead = , /// 替换原方法
MDAspectPositionBefore = , /// 原方法执行前调用 MDAspectOptionAutomaticRemoval = << /// Will remove the hook after the first execution.
};

  2. 配置文件

配置hook的类,hook时机,实例方法和类方法,以及回调处理

为了区分实例方法和类方法,需要在类方法前加一个“+”

+(NSDictionary *)AOP_MDViewControllerConfigDic{

    NSDictionary *configDic = @{
@"MDViewController":@{//hook那个类名
@"TrackEvents":@[
@{//实例方法
@"moment":@"before",//hook之前调用
@"EventSelectorName":@"instanceMethod",//实例方法名
@"block":^(id<MDAspectInfo>aspectInfo){//回调处理
// 获取方法的参数
NSLog(@"跳转");
},
},
@{//类方法
@"moment":@"instead",//替换原方法
@"EventSelectorName":@"+hookClassMethod",//类方法名
@"block":^(id<MDAspectInfo>aspectInfo){//回调处理
// 获取方法的参数
NSLog(@"到处可以hook到我");
},
},
]
},
};
return configDic;
}

  3. 解析管理类  

// hook到方法回调,完全控制
typedef void (^AspectEventBlock)(id<MDAspectInfo> aspectInfo); @implementation MDAOPManager +(void)load{ // 加载配置文件
NSMutableDictionary *mutableDic = [NSMutableDictionary dictionary];
[mutableDic addEntriesFromDictionary:[MDAOPManager AOP_MDViewControllerConfigDic]];
[mutableDic addEntriesFromDictionary:[MDAOPManager AOP_MDSecViewControllerConfigDic]];
[self configAOPWithDic:mutableDic]; } +(void)configAOPWithDic:(NSDictionary *)configDic{
// 解析配置文件
for (NSString *className in configDic) {
Class clazz = NSClassFromString(className);//拿到类名
NSDictionary *config = configDic[className];//配置信息
NSArray *trackArr = config[@"TrackEvents"];//方法数组
if (trackArr) {
for (NSDictionary *event in trackArr) { AspectEventBlock buttonBlock = event[@"block"];//回调
NSString *method = event[@"EventSelectorName"];//方法名
NSString *moment = event[@"moment"];//hook时机 MDAspectOptions option = MDAspectPositionAfter;
if ([moment isEqualToString:@"before"]) {
option = MDAspectPositionBefore;
}else if ([moment isEqualToString:@"instead"]){
option = MDAspectPositionInstead;
} SEL selector = NSSelectorFromString(method); if ([method hasPrefix:@"+"]) {//hook类方法
method = [method substringFromIndex:];
selector = NSSelectorFromString(method); [clazz aspect_hookClassSelector:selector withOptions:option usingBlock:^(id<MDAspectInfo> aspectInfo) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, ), ^{
buttonBlock(aspectInfo);
});
} error:NULL];
}else{//hook实例方法 [clazz aspect_hookSelector:selector withOptions:option usingBlock:^(id<MDAspectInfo> aspectInfo) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, ), ^{
buttonBlock(aspectInfo);
});
} error:NULL];
}
}
}
}
}

4. 对外接口

// 类直接调用,hook实例方法
+ (id<MDAspectToken>)aspect_hookSelector:(SEL)selector withOptions:(MDAspectOptions)options usingBlock:(id)block error:(NSError **)error;
// 对象调用,hook实例方法
- (id<MDAspectToken>)aspect_hookSelector:(SEL)selector withOptions:(MDAspectOptions)options usingBlock:(id)block error:(NSError **)error;
// 类直接调用,hook类方法
+ (id<MDAspectToken>)aspect_hookClassSelector:(SEL)selector withOptions:(MDAspectOptions)options usingBlock:(id)block error:(NSError *__autoreleasing *)error;

// 对象调用,hook类方法
- (id<MDAspectToken>)aspect_hookClassSelector:(SEL)selector withOptions:(MDAspectOptions)options usingBlock:(id)block error:(NSError *__autoreleasing *)error;

说明:MDAspect是对Aspects的扩展,添加了hook类方法的支持,希望能够帮助大家~







iOS AOP实战的更多相关文章

  1. 包建强的培训课程(11):iOS Runtime实战

    @import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/c ...

  2. Cordova - 使用Cordova开发iOS应用实战3(添加Cordova控制台插件)

    Cordova - 使用Cordova开发iOS应用实战3(添加Cordova控制台插件) 前文介绍了通过 Safari 的 Web检查器,可以看到控制台输出的信息.但有时这样调试代码不太方便,如果在 ...

  3. Cordova - 使用Cordova开发iOS应用实战2(生命周期、使用Safari调试)

    Cordova - 使用Cordova开发iOS应用实战2(生命周期.使用Safari调试) 前文我们创建了一个简单的Cordova项目,结构如下: 1,Cordova生命周期事件 (1)device ...

  4. Cordova - 使用Cordova开发iOS应用实战1(配置、开发第一个应用)

    Cordova - 使用Cordova开发iOS应用实战1(配置.开发第一个应用) 现在比较流行使用 html5 开发移动应用,毕竟只要写一套html页面就可以适配各种移动设备,大大节省了跨平台应用的 ...

  5. iOS开发——实战OC篇&环境搭建之Xib(玩转UINavigationController与UITabBarController)

    iOS开发——实战OC篇&环境搭建之Xib(玩转UINavigationController与UITabBarController)   前面我们介绍了StoryBoard这个新技术,和纯技术 ...

  6. iOS开发——实战OC篇&环境搭建之纯代码(玩转UINavigationController与UITabBarController)

    iOS开发——实战OC篇&环境搭建之纯代码(玩转UINavigationController与UITabBarController)   这里我们就直接上实例: 一:新建一个项目singleV ...

  7. rabbitmq在ios中实战采坑

    1. rabbitmq在ios中实战采坑 1.1. 问题 ios使用rabbitmq连接,没过多久就断开,并报错.且用android做相同的步骤并不会报错,错误如下 Received connecti ...

  8. iOS逆向实战与工具使用(微信添加好友自动确认)

    iOS逆向实战与工具使用(微信添加好友自动确认) 原文链接 源码地址 WeChatPlugin-iOS Mac OS 版微信小助手(远程控制.消息防撤回.自动回复.微信多开) 一.前言 本篇主要实现在 ...

  9. Xamarin iOS开发实战第1章使用C#编写第一个iOS应用程序

    Xamarin iOS开发实战第1章使用C#编写第一个iOS应用程序 C#原本是用来编写Windows以及Windows Phone的应用程序.自从Xamarin问世后.C#的作用就发生了非常大的变化 ...

随机推荐

  1. 深入理解 BigDecimal

    .katex { display: block; text-align: center; white-space: nowrap; } .katex-display > .katex > ...

  2. Go游戏服务端框架从零搭建(一)— 架构设计

    五邑隐侠,本名关健昌,10年游戏生涯,现隐居海边. 本教程以Go语言分区游戏服务端框架搭建为例. Go语言是Google开发的一种静态强类型.编译型.并发型.具有垃圾回收功能的编程语言.语法上近似C语 ...

  3. k8s 开船记-首航:博客站点从 docker swarm 切换到 k8s

    昨天晚上,我们将博客站点的生产环境从 docker swarm 集群切换到了 k8s 集群,开船到目前,航行非常平稳,可以说首航成功! k8s 集群是我们用10台阿里云服务器自己搭建的,1台 mast ...

  4. vue 各种打包坑

    1,报错 Refused to load the image 'http://localhost:8080/favicon.ico' because it violates the following ...

  5. [TimLinux] Python 元类

    1. type函数 name = "This is a string" print(type(name)) # <class 'str'> print("*& ...

  6. HDU3247 Resource Archiver (AC自动机+spfa+状压DP)

    Great! Your new software is almost finished! The only thing left to do is archiving all your n resou ...

  7. 2018HDU多校训练一 A - Maximum Multiple

    Given an integer nn, Chiaki would like to find three positive integers xx, yy and zzsuch that: n=x+y ...

  8. ARTS-S mac终端ftp命令行上传下载文件

    上传 ftp -u ftp://root:123456@10.11.12.3/a.txt a.txt 下载 ftp -o a.txt ftp://root:123456@10.11.12.13/a.t ...

  9. 【Java Web开发学习】跨域请求

    [Java Web开发学习]跨域请求 ================================================= 1.使用jsonp ===================== ...

  10. 【Java Web开发学习】Spring MVC整合WebSocket通信

    Spring MVC整合WebSocket通信 目录 ========================================================================= ...