Objective-C 方法交换实践(三) - Aspects 源码解析
一、类与变量
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 源码解析的更多相关文章
- Istio技术与实践02:源码解析之Istio on Kubernetes 统一服务发现
前言 文章Istio技术与实践01: 源码解析之Pilot多云平台服务发现机制结合Pilot的代码实现介绍了Istio的抽象服务模型和基于该模型的数据结构定义,了解到Istio上只是定义的服务发现的接 ...
- Android Handler机制(三)----Looper源码解析
一.Looper Looper对象,顾名思义,直译过来就是循环的意思,从MessageQueue中不断取出message. Class used to run a message loop for a ...
- ThreadPoolExecutor系列三——ThreadPoolExecutor 源码解析
ThreadPoolExecutor 源码解析 本文系作者原创,转载请注明出处:http://www.cnblogs.com/further-further-further/p/7681826.htm ...
- 三.jQuery源码解析之jQuery的框架图
这张图片是对jQuery源码截图,一点一点拼出来的. 现在根据这张图片来对jQuery框架做一些说明. 一.16~9404行可以发现,最外层是一个自调用函数.当jQuery初始化时,这个自调用函数包含 ...
- 多线程与高并发(三)—— 源码解析 AQS 原理
一.前言 AQS 是一个同步框架,关于同步在操作系统(一)-- 进程同步 中对进程同步做了些概念性的介绍,我们了解到进程(线程同理,本文基于 JVM 讲解,故下文只称线程)同步的工具有很多:Mutex ...
- Istio技术与实践01: 源码解析之Pilot多云平台服务发现机制
服务模型 首先,Istio作为一个(微)服务治理的平台,和其他的微服务模型一样也提供了Service,ServiceInstance这样抽象服务模型.如Service的定义中所表达的,一个服务有一个全 ...
- Aspects源码解析(转载)
文章来源:https://www.jianshu.com/p/2c93446d86bd
- Spring Boot系列(三):Spring Boot整合Mybatis源码解析
一.Mybatis回顾 1.MyBatis介绍 Mybatis是一个半ORM框架,它使用简单的 XML 或注解用于配置和原始映射,将接口和Java的POJOs(普通的Java 对象)映射成数据库中的记 ...
- Android源码解析系列
转载请标明出处:一片枫叶的专栏 知乎上看了一篇非常不错的博文:有没有必要阅读Android源码 看完之后痛定思过,平时所学往往是知其然然不知其所以然,所以为了更好的深入Android体系,决定学习an ...
随机推荐
- JQ的几组API辨析:
1.插入: Jq的插入一共有八个API可供选择,结果相类似,下面将以例子,简单明了的介绍下用法: <select name="one" multiple="mult ...
- js解决千分符问题[收藏下]
//js数字千分符处理 function commafy(num) { num = num + ""; var re = /(-?\d+)(\d{3})/ while (re.te ...
- MySQL数据库(13)----忘记root用户密码解决方案【转载】
1.首先确认服务器出于安全的状态,也就是没有人能够任意地连接MySQL数据库. 因为在重新设置MySQL的root密码的期间,MySQL数据库完全出于没有密码保护的 状态下,其他的用户也可以任意地登录 ...
- 新年开篇-ERP和OA集成步骤
1.备份要升级帐套的数据库 6点 - 6点10分完成 重启 服务器 2.升级数据库 6点30 - 7点 3.配置ERP电子表单和EasyFlow表单 7点 - 7点30分 录入多公司信息(电子签核), ...
- win10命令控制符
IP:ipconfigIP地址侦测器:Nslookup显卡:dxdiag控制面板:control电话拨号:dialer木马捆绑工具,系统自带:iexpress本地用户和组:lusrmgr.msc鼠标属 ...
- vmware虚拟机安装CentOS教程
linux是企业最常用的服务器系统之一,CentOS是免费的,所以用的企业也挺多,今天给大家分享怎么在自己电脑的虚拟机中安装CentOS-6.5,以便用来玩耍,没事的时候可以学学linux的一些知识. ...
- GitHub初步探索-1-使用本地代码管理工具,简化上传的过程
使用GitHub对于我们写Java的同志们来说是一个非常好的代码存储的方式,但是因为是全英文的,操作起来有一点复杂,所以我不是经常使用 ,但是最近代码越敲越多,再加上老师要求,希望使用比较简单的方法来 ...
- java笔记--局部内部类认识与理解
java内部类 内部类应用最多的场景是在编写GUI程序时,将大量的事件监听处理放在了内部类中进行 --如果朋友您想转载本文章请注明转载地址"http://www.cnblogs.com/XH ...
- win10系统80端口被System (PID=4)占用的解决
今天想用wamp搭建虚拟目录.发现80端口被占用,操作挺麻烦的,所以想要更改. 具体流程如下: 1.“win+R”输入“cmd”,然后输入“netstat -ano | findstr "8 ...
- 前端静态资源版本更新与缓存之——通过gulp 在原html文件上自动化添加js、css版本号
原理 修改js和css文件 通过对js,css文件内容进行hash运算,生成一个文件的唯一hash字符串(如果文件修改则hash号会发生变化) 替换html中的js,css文件名,生成一个带版本号的文 ...