typedef NS_OPTIONS(NSUInteger, AspectOptions) { AspectPositionAfter = 0, /// 原方法以后 (default) AspectPositionInstead = 1, /// 替换原方法 AspectPositionBefore = 2, /// 原方法以前 AspectOptionAutomaticRemoval = 1 << 3 /// 执行一次后就移除 };
存储AspectIdentifier
,总共有三个数组,分别存储 上面的 After Instead Before 的各类 Aspects。数组
+ (instancetype)identifierWithSelector:(SEL)selector object:(id)object options:(AspectOptions)options block:(id)block error:(NSError **)error;
从建立方法就能够看出,他是用来记录 要替换的对象object
,替换的原方法selector
,替换的类型options
,以及执行的代码block
。其中block
的参数是 id<AspectInfo>
类型的。ide
一种是协议名,标记当前 NSinvocation
的一些环境atom
@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
一种是类名,基本上就是实现上面的协议的类。lua
@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
aspect_isSelectorAllowedAndTrack
检测是否可以swizzle检测不能是如下方法 @"retain", @"release", @"autorelease", @"forwardInvocation:"code
对于"dealloc"方法位置只能是 AspectPositionBefore对象
被交换的方法是否未实现get
若是是metaClass,若是子类已经hook,返回;若是父类已经hook,返回。否者标记hook的 SEL,为父类标记已经hook 的 Child Class。it
aspect_getContainerForObject
获得当前 select 对应的 AspectsContainer, 不存在就建立,经过关联对象的方式存储在类中io
AspectIdentifier
建立 AspectIdentifier
而且添加到AspectsContainer里面去class
aspect_prepareClassAndHookSelector
进行swizzle操做若是已经操做过,返回
不然建立一个 subclass ,对其进行 object_setClass 操做,而后对这个 subclass 进行 A 操做,以后把 当前对象的 isa 指向 subclass
A操做是:
替换类的 forwardInvocation
方法为 __ASPECTS_ARE_BEING_CALLED__
为类增长 aliasSelector
指向原 selector
把原 selector
指向 _objc_msgForward
或者_objc_msgForward_stret
固然里面还有一些容错判断
__ASPECTS_ARE_BEING_CALLED__
流程取出当前对象(object)的 AspectsContainer 和 类(class)的 AspectsContainer ,调用 Before hooks 的一些方法,调用 instead 的方法,调用 after 的方法
对没有instead的状况检测是否有原方法,没有就走原 forwardInvocation
方法或者走 doesNotRecognizeSelector
方法