一、类与变量

AspectOptions
typedef NS_OPTIONS(NSUInteger, AspectOptions) {

    AspectPositionAfter   = 0,            /// 原方法之后 (default)

    AspectPositionInstead = 1,            /// 替换原方法

    AspectPositionBefore  = 2,            /// 原方法之前

    AspectOptionAutomaticRemoval = 1 << 3 /// 执行一次后就移除

};

AspectsContainer

存储AspectIdentifier ,总共有三个数组,分别存储 上面的 After Instead Before 的各种 Aspects。

AspectIdentifier
+ (instancetype)identifierWithSelector:(SEL)selector object:(id)object options:(AspectOptions)options block:(id)block error:(NSError **)error;

从创建方法就可以看出,他是用来记录 要替换的对象object,替换的原方法selector,替换的类型options,以及执行的代码block。其中block的参数是 id<AspectInfo>类型的。

AspectInfo

一种是协议名,标记当前 NSinvocation的一些环境

@protocol AspectInfo <NSObject>

/// The instance that is currently hooked.
- (id)instance; /// The original invocation of the hooked method.
- (NSInvocation *)originalInvocation; /// All method arguments, boxed. This is lazily evaluated.
- (NSArray *)arguments; @end

一种是类名,基本上就是实现上面的协议的类。

@interface AspectInfo : NSObject <AspectInfo>
- (id)initWithInstance:(__unsafe_unretained id)instance invocation:(NSInvocation *)invocation;
@property (nonatomic, unsafe_unretained, readonly) id instance;
@property (nonatomic, strong, readonly) NSArray *arguments;
@property (nonatomic, strong, readonly) NSInvocation *originalInvocation;
@end

二、具体过程

1.aspect_isSelectorAllowedAndTrack 检测是否能够swizzle

检测不能是以下方法 @"retain", @"release", @"autorelease", @"forwardInvocation:"

对于"dealloc"方法位置只能是 AspectPositionBefore

被交换的方法是否未实现

如果是metaClass,如果子类已经hook,返回;如果父类已经hook,返回。否者标记hook的 SEL,为父类标记已经hook 的 Child Class。

2.aspect_getContainerForObject

得到当前 select 对应的 AspectsContainer, 不存在就创建,通过关联对象的方式存储在类中

3.AspectIdentifier

创建 AspectIdentifier 并且添加到AspectsContainer里面去

4.aspect_prepareClassAndHookSelector 进行swizzle操作
  • 如果已经操作过,返回

  • 如果是metaClass,对metaClass 进行 A操作

  • 如果实例对象进行过 object_setClass 操作,对 class 进行A操作

  • 否则创建一个 subclass ,对其进行 object_setClass 操作,然后对这个 subclass 进行 A 操作,之后把 当前对象的 isa 指向 subclass

A操作是:

替换类的 forwardInvocation 方法为 __ASPECTS_ARE_BEING_CALLED__

为类增加 aliasSelector 指向原 selector

把原 selector 指向 _objc_msgForward 或者_objc_msgForward_stret

当然里面还有一些容错判断

5.__ASPECTS_ARE_BEING_CALLED__ 流程

取出当前对象(object)的 AspectsContainer 和 类(class)的 AspectsContainer ,调用 Before hooks 的一些方法,调用 instead 的方法,调用 after 的方法

对没有instead的情况检测是否有原方法,没有就走原 forwardInvocation方法或者走 doesNotRecognizeSelector 方法

Objective-C 方法交换实践(三) - Aspects 源码解析的更多相关文章

  1. Istio技术与实践02:源码解析之Istio on Kubernetes 统一服务发现

    前言 文章Istio技术与实践01: 源码解析之Pilot多云平台服务发现机制结合Pilot的代码实现介绍了Istio的抽象服务模型和基于该模型的数据结构定义,了解到Istio上只是定义的服务发现的接 ...

  2. Android Handler机制(三)----Looper源码解析

    一.Looper Looper对象,顾名思义,直译过来就是循环的意思,从MessageQueue中不断取出message. Class used to run a message loop for a ...

  3. ThreadPoolExecutor系列三——ThreadPoolExecutor 源码解析

    ThreadPoolExecutor 源码解析 本文系作者原创,转载请注明出处:http://www.cnblogs.com/further-further-further/p/7681826.htm ...

  4. 三.jQuery源码解析之jQuery的框架图

    这张图片是对jQuery源码截图,一点一点拼出来的. 现在根据这张图片来对jQuery框架做一些说明. 一.16~9404行可以发现,最外层是一个自调用函数.当jQuery初始化时,这个自调用函数包含 ...

  5. 多线程与高并发(三)—— 源码解析 AQS 原理

    一.前言 AQS 是一个同步框架,关于同步在操作系统(一)-- 进程同步 中对进程同步做了些概念性的介绍,我们了解到进程(线程同理,本文基于 JVM 讲解,故下文只称线程)同步的工具有很多:Mutex ...

  6. Istio技术与实践01: 源码解析之Pilot多云平台服务发现机制

    服务模型 首先,Istio作为一个(微)服务治理的平台,和其他的微服务模型一样也提供了Service,ServiceInstance这样抽象服务模型.如Service的定义中所表达的,一个服务有一个全 ...

  7. Aspects源码解析(转载)

    文章来源:https://www.jianshu.com/p/2c93446d86bd

  8. Spring Boot系列(三):Spring Boot整合Mybatis源码解析

    一.Mybatis回顾 1.MyBatis介绍 Mybatis是一个半ORM框架,它使用简单的 XML 或注解用于配置和原始映射,将接口和Java的POJOs(普通的Java 对象)映射成数据库中的记 ...

  9. Android源码解析系列

    转载请标明出处:一片枫叶的专栏 知乎上看了一篇非常不错的博文:有没有必要阅读Android源码 看完之后痛定思过,平时所学往往是知其然然不知其所以然,所以为了更好的深入Android体系,决定学习an ...

随机推荐

  1. 浏览器根对象window之窗体和工具条

    1. 窗体和工具条 1.1 窗体 frames.self.window.parent.top.opener. frames 数组类型,页面中iframe的引用,如果页面有2个iframe,则frame ...

  2. webstorm 打开后 一直停留在scanning files to index....,或跳出内存不够的提示框

    用着有时会这样,超级卡, 网上搜了下,原来如此,记录下,免得忘了. ------------------------- 说明: 在npm install 后,会出现Scanning files to ...

  3. Hadoop、Hive、Spark 之间关系

    作者:Xiaoyu Ma ,大数据工程师 大数据本身是个很宽泛的概念,Hadoop生态圈(或者泛生态圈)基本上都是为了处理超过单机尺度的数据处理而诞生的.你可以把它比作一个厨房所以需要的各种工具.锅碗 ...

  4. Android LinkedList和ArrayList的区别

    LinkedeList和ArrayList都实现了List接口,但是它们的工作原理却不一样.它们之间最主要的区别在于ArrayList是可改变大小的数组,而LinkedList是双向链接串列(doub ...

  5. netstat 检测及监测网络连接

    网站没有很多流量,可查带宽却跑了几十M? 这是什么情况呢?      如果是出现这种情况,不排除是被CC了的可能.那么如何确定是否真的被CC了,被CC又有什么对应政策呢? netstat -na ,用 ...

  6. SQL Server ->> ColumnStore Index(列存储索引)

    Columnstored index是SQL Server 2012后加入的重大特性,数据不再以heap或者B Tree的形式存储(row level)存储在每一个数据库文件的页里面,而是以列为单位存 ...

  7. 【Leetcode】【Medium】Add Two Numbers

    You are given two linked lists representing two non-negative numbers. The digits are stored in rever ...

  8. PHP-FPM详解

    目录 作用 安装 全局配置 配置进程池 参考Company开发环境 转发请求给PHP-FPM 思考 作用 PHP-FPM(PHP FastCGI Process Manager)意:PHP FastC ...

  9. 深入浅出SharePoint——定制保存Item按钮

    <script type="text/javascript" src="/_layouts/style/jquery-1.4.4.min.js">& ...

  10. unittest:2 执行多条用例,仅执行一次setUp和tearDown

    对象方法setUp()和tearDown() 每个用例执行前后都会被调用.但是有另外一种场景:setUp之后执行完所有用例,最后调用一次tearDown.比如打开网页,多条用例分别验证网页上的元素正确 ...