设为首页 加入收藏

TOP

iOS AOP实战(一)
2019-09-03 03:40:34 】 浏览:104
Tags:iOS AOP 实战

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   = 0,            /// 默认,当原方法执行完调用
    MDAspectPositionInstead = 1,            /// 替换原方法
    MDAspectPositionBefore  = 2,            /// 原方法执行前调用
    
    MDAspectOptionAutomaticRemoval = 1 << 3 /// 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:1];
                    selector = NSSelectorFromString(method);

                    [clazz aspect_hookClassSelector:selector withOptions:option usingBlock:^(id<MDAspectInfo> aspectInfo) {
                        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                            butto
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇iOS代码混淆 下一篇【原】UILabel 设置了 attributed..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目