Aspects 源码分析

Aspects

分析- (id<AspectToken>)aspect_hookSelector:(SEL)selector                      withOptions:(AspectOptions)options                       usingBlock:(id)block                            error:(NSError **)error 

aspect_add:主要步骤

自旋锁执行下面hook操作,

1.取出AspectsContainer 对像,通过关联对象存储的值。

2.通过传入的selector,obj,block,等参数初始化AspectIdentifier,将AspectIdentifier 添加到AspectsContainer数组中去。

3.执行aspect_prepareClassAndHookSelector(self, selector, error);这个方法主要去给对象添加一个子类或者给类hook forwarding方法。后面详细分析aspect_prepareClassAndHookSelector的具体分析,

aspect_add代码如下:

中间类代码:

里面涉及到的中间类分析

1.AspectIdentifier 这个是每个hook 保存的aspect ,包含selector,block,blockSignature,object,options,其中blockSignature这个很重要,用到结构体去对应block,通过指针偏移查找到blockSignature,结构体代码如下:


2.AspectsContainer 这个类是用来保存所有的AspectIdentifier//Tracks all aspects for an object/class,,有三种数组beforeAspects,insteadAspects,afterAspects,(copy,atomic)属性。

3.AspectTracker 这个是打上标志的类,如果当前类已经hook了一个类方法,这个类及其父类都会保存selectorName,下次hook直接判断,不能再hook。

aspect_prepareClassAndHookSelector的具体分析代码如下:


1.aspect_hookClass的主要作用判断是否有后缀AspectsSubclassSuffix,说明之前hook过这个对象,中间类已经生成,判断是否元类,或者kvo之类的有过中间类,这2种情况直接aspect_swizzleForwardInvocation(klass); 就是__ASPECTS_ARE_BEING_CALLED__与 forwardInvocation进行方法交换。static NSString *const AspectsForwardInvocationSelectorName = @"__aspects_forwardInvocation:"; 这个AspectsForwardInvocationSelectorName对应原来的forwardInvocation的IMP

 IMP originalImplementation = class_replaceMethod(klass, @selector(forwardInvocation:), (IMP)__ASPECTS_ARE_BEING_CALLED__, "v@:@");

if (originalImplementation) {class_addMethod(klass,         NSSelectorFromString(AspectsForwardInvocationSelectorName), originalImplementation, "v@:@");}

如果没有hook过的对象,则创建中间类objc_allocateClassPair,objc_registerClassPair,aspect_hookedGetClass重定向class方法,使子类对象class方法返回base类对象,隐藏子类 aspect_hookedGetClass(subclass, statedClass) ,同时对forwardInvocation也进行方法交换

2.aspect_isMsgForwardIMP(targetMethodIMP) 判断原来selector 的IMP 是否是_objc_msgForward,如果没有,就新增一个带有AspectsMessagePrefix前缀的方法,并指向原seletor的IMP,原来seletor的imp指向!defined(__arm64__) ?_objc_msgForward :_objc_msgForward_stret这样最终方法都会走消息转发_objc_msgForward,最后会走到__ASPECTS_ARE_BEING_CALLED__

__ASPECTS_ARE_BEING_CALLED__的详细分析代码


1. AspectInfo *info = [[AspectInfo alloc] initWithInstance:self invocation:invocation];初始化一个AspectInfo对象,这个对象包含调用者和invocationaspect_invoke(aspects, info) 这个从AspectsContainer 当中的三个数组,去调度 这个info

具体核心调用代码如下:

1.用identirefier里的blocksign 去初始化一个调度者NSInvocation *blockInvocation = [NSInvocation invocationWithMethodSignature:self.blockSignature],从传入的info信息里面拿到NSInvocation *originalInvocation = info.originalInvocation,对比2个调度者参数信息,如果不一致返回NO,报错,然后从第二个参数开始遍历originalInvocation的参数传入到 blockInvocation,[originalInvocation getArgument:argBuf atIndex:idx];[blockInvocation setArgument:argBuf atIndex:idx];

最后设置blockInvocation的target,并invoke,[blockInvocation invokeWithTarget:self.block]这就是block的调用。依次执行classContainer.beforeAspects , classContainer.insteadAspects , classContainer.afterAspects重的block,如果是AspectPositionInstead的会替换aliasSelector的执行。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 转摘自面向切面编程 1. 背景 最近在做项目的打点统计的时候,发现业务逻辑和打点逻辑经常耦合在一起,这样一方面影响...
    Arthurcsh阅读 678评论 1 1
  • 1 aspects简介 1.1 Aspect Oriented Programming简介 面向切面编程(Aspe...
    奚山遇白阅读 827评论 0 0
  • 前言 如何把这个世界变得美好?把你自己变得更美好 我们这篇博客继续来介绍Runtime在开发中的实际应用,通过开源...
    Dely阅读 2,191评论 4 16
  • 0.面向切面编程 摘自网络: 在开发过程中,面向切面编程是通过预编译方式和运行期动态代理实现程序功能的统一维护的一...
    FY_Chao阅读 214评论 0 0
  • 我们一定要给自己提出这样的任务:第一,学习,第二是学习,第三还是学习。 —— 列宁 前面几章大概的说了一下iOS的...
    郭小弟阅读 15,401评论 1 34