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
方法