iOS中的AOP(2)-SFAspect的实现原理

概述

上一篇文章说起到了AOP的概念和一些应用例子,以及SFAspect是基于消息转发实现AOP的,这一篇文章主要是讲述SFAspect的实现原理缓存

AOP实现原理

  • 前置知识:runtime
  • 如何利用runtime进行hook
  • 执行hook的操做
  • hook的撤销和类的销毁
  • 其余细节

runtime

SFAspect是基于runtime中的消息转发去实现的,由于runtime的知识点涉及到比较多,这里放在另外的文章去分析markdown

  • rumtime概览
  • 消息发送和消息转发机制

iOS runtime中说明了像OC中面向对象的基础,和消息发送机制的概述流程函数

objc库源码分析(3)-方法调用-消息发送objc库源码分析(3)-方法调用-消息转发 中,从objc源码中详细分析了消息发送和消息转发的详细流程源码分析


如何利用runtime进行hook

Objective-c中的函数调用实际上是转换成objc_msgSend系列的函数调用,也就是消息发送,post

调用objc_msgSend()时会传入接受对象target和方法名称sel以及参数。在objc_msgSend函数回去查找方法缓存,看类的缓存是否存在方法sel对应的方法实现IMP。若是找不到,就会执行lookUpImpOrForward()方法去查找sel对应的IMP.spa

在lookUpImpOrForward()中会去查找方法的IMP,若是找不到,就会进入到动态解析过程,若是仍是找不到方法实现,就会将该sel对应的IMP设置为_objc_msgForward,并存入到方法的缓存中。将IMP设置为forward_imp,也就是说方法调用即将进入消息转发流程。指针

消息转发过程当中有两个步骤 1 查找替代执行的对象,也就会调用forwardingTargetForSelector方法 2 若是找不到替代执行的对象,则会内部消化,调用methodSignatureForSelector获取方法签名和调用forwardInvocation执行自定义操做code

SFAspect的实现正是经过将被调用方法的sel对应的IMP设置为_objc_msgForward,让调用方法进入消息转发流程,并在自定义的methodSignatureForSelector和forwardInvocation中进行自定义的操做去实现AOP功能。以下图orm

经过方法交换的方法去实现为类添加自定义methodSignatureForSelector和forwardInvocation方法,而后在自定义的forwardInvocation执行咱们须要的操做,去实现OC中的Hook。对象


执行hook的操做

上面提到,会在自定义的forwardInvocation执行咱们须要的操做,那如何在forwardInvocation中执行自定义的操做呢?

  1. 封装

首先调用hookSel或hookAllClassSel的时候,咱们会把hookSel和hookAllClassSel里面的内容(被hook的对象,hook的ID,优先级,sel以及操做block)包装成一个SFAspectModel对象

  1. 绑定

将SFAspectModel对象添加到被hook对象的SFAspectContainer中,SFAspectContainer 是一个管理被hook对象全部的hook内容的容器类。SFAspectContainer是经过动态绑定objc_setAssociatedObject绑定到对象的类中(若是对象是实例,则绑定到类中,若是对象是类,则绑定到类对应的元类中)

  1. 操做

当调用hook方法的时候,进入到消息转发流程,执行自定义的forwardInvocation的时候。在自定义的forwardInvocation中取出被hook对象的SFAspectContainer容器,拿到容器中的SFAspectModel对象,取出SFAspectModel对象的操做block

上面的三个步骤关系以下图所示

经过强制使方法调用进入消息转发和上述操做步骤后,就能够实现Hook一个方法了。

在SFAspect中能够经过hookAllSel去hook一个类全部实例的对象,也能够经过hookSel去hook一个对象。

  • 对于hook一个类全部实例的对象,是在对象的类中去进行图中的步骤
  • 对于hook一个对象,是经过动态生成一个子类,再将对象的isa指针指向新建的子类(和KVO的实现方式一致),而后在子类中进行上图的操做

hook的撤销后续操做和类的还原

  • 中止后续操做

SFAspect中能够经过调用SFAspectModel的stop方法中止后续操做,其实实现的方式也特别简单,就是经过抛出异常去实现的。当咱们对方法进行hook的时候,没进行一个hook操做都会用try catch去捕获异常,以下图所示

在调用stop函数时,就会抛出一个Error,当catch到这个error的时候,就会退出forwardInvocation函数

  • 关于类的还原

当咱们调用removeHook方法的时候,会在对象的类的SFAspectContainer中检查是否有该sel的hook对象SFAspectModel,若是有,则删除。 当SFAspectContainer为空的时候,就会销毁SFAspectContainer。并同时重置被hook的方法,methodSignatureForSelector和forwardInvocation方法,


其余细节

文章中有些细节没有提价到,如hook优先级的控制,动态生成子类的释放,锁操做等 代码很少,若是感兴趣的童鞋能够下载源码看一下

相关文章
相关标签/搜索