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. 产品vs程序员:你知道www是怎么来的吗?

    精彩回顾: 我是一个explorer的线程 我是一个杀毒软件线程 我是一个IE浏览器线程 比特宇宙-TCP/IP的诞生 Unix.Linux.Windows三大帝国集团发表<关于比特宇宙推进经贸 ...

  2. Redis面试热点之底层实现篇(续)

    0.题外话 接着昨天的[决战西二旗]|Redis面试热点之底层实现篇继续来了解一下ziplist压缩列表这个数据结构. 你可能会抱有疑问:我只是使用Redis的功能并且公司的运维同事都已经搭建好了平台 ...

  3. iOS 手势及触摸

    转自:http://justsee.iteye.com/blog/1885538 一.响应链 在IOS开发中会遇到各种操作事件,通过程序可以对这些事件做出响应. 首先,当发生事件响应时,必须知道由谁来 ...

  4. 配置中心入门案例以及出现Could not resolve placeholder 'XXX' in value "${XXX}"的解决方式

    编写配置中心的服务端 创建项目 修改 pom 文件添加 config-server 坐标 <?xml version="1.0" encoding="UTF-8&q ...

  5. 转化欧拉回路(难题)-UESTC-1957励志的猴子

    励志的猴子 Time Limit: 1000 MS     Memory Limit: 256 MB Submit Status 上图是2013南京亚青会吉祥物圆圆.自从它诞生以来,它就被吐槽为最丑吉 ...

  6. 【React】377- 实现 React 中的状态自动保存

    点击上方"前端自习课"关注,学习起来~ 作者:陈俊宇 https://github.com/CJY0208 什么是状态保存? 假设有下述场景: 移动端中,用户访问了一个列表页,上拉 ...

  7. markdownPad在win10下渲染报错问题

    今天使用MarkdownPad 2,打开后发现预览效果出错了,本来以为自己下载了破解版的缘故导致软件不稳定,后来查找了网上,发现这是一个普遍的问题,根据软件的提示来到官方FAQ页面,找到解决方法. 实 ...

  8. IoTClient开发5 - ModBusRtu协议

    前言 前面我们介绍了ModBusTcp协议.今天我们接着来介绍ModBusRtu协议.和ModBusTcp不同的是ModBusRtu基于串口通信,ModBusTcp是基于Tcp以太网通信. 所以我们在 ...

  9. Python递归函数如何写?正确的Python递归函数用法

    前言本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理.在函数内部,可以调用其他函数.如果一个函数在内部调用自身本身,这个函数就是递归 ...

  10. v-if和v-show 的区别

    区别 1.手段:v-if是通过控制dom节点的存在与否来控制元素的显隐:v-show是通过设置DOM元素的display样式,block为显示,none为隐藏: 2.编译过程:v-if切换有一个局部编 ...