『iOS的第三方庫(kù)』Aspects

涉及到的知識(shí)點(diǎn)有:消息轉(zhuǎn)發(fā)TODOMethod-SwizzlingTODO,動(dòng)態(tài)方法TODOKVO(暫無(wú)),AOP等。
下載地址

概述

Aspects是一個(gè)輕量級(jí)的、支持Objective-C&Swift語(yǔ)言的AOP實(shí)現(xiàn)。可以把Aspects當(dāng)做Method-SwizzlingTODO的一種應(yīng)用。它允許你在每個(gè)類或每個(gè)實(shí)例已有方法中添加代碼,可以設(shè)置切入點(diǎn)為after /instead/before等。比起常規(guī)的Method-SwizzlingTODO,Aspects會(huì)自動(dòng)調(diào)用super方法,并且使用起來(lái)更加簡(jiǎn)單、方便。
Aspects利用OC的消息轉(zhuǎn)發(fā)機(jī)制,hook消息。這樣會(huì)有一些性能開銷,因此不要把Aspects加到經(jīng)常被使用的方法里面。Aspects是用來(lái)設(shè)計(jì)給View/Controller代碼使用的,而不是用來(lái)hook每秒調(diào)用1000次的方法的。因此Aspects不應(yīng)該被用在for循環(huán)這些方法里面,會(huì)造成很大的性能損耗。
Aspects是不支持hook 靜態(tài)static方法的。

這里還有一些簡(jiǎn)介需要翻譯,后續(xù)補(bǔ)上。TODO

使用方法

Aspects是NSObject的一個(gè)extension,只要是NSObject,都可以使用這兩個(gè)方法。一個(gè)是用來(lái)hook類方法的,一個(gè)是hook實(shí)例方法的。

/// Adds a block of code before/instead/after the current `selector` for a specific class.
///
/// @param block Aspects replicates the type signature of the method being hooked.
/// The first parameter will be `id<AspectInfo>`, followed by all parameters of the method.
/// These parameters are optional and will be filled to match the block signature.
/// You can even use an empty block, or one that simple gets `id<AspectInfo>`.
///
/// @note Hooking static methods is not supported.
/// @return A token which allows to later deregister the aspect.
+ (id<AspectToken>)aspect_hookSelector:(SEL)selector
                           withOptions:(AspectOptions)options
                            usingBlock:(id)block
                                 error:(NSError **)error;

/// Adds a block of code before/instead/after the current `selector` for a specific instance.
- (id<AspectToken>)aspect_hookSelector:(SEL)selector
                           withOptions:(AspectOptions)options
                            usingBlock:(id)block
                                 error:(NSError **)error;

添加Aspects后,會(huì)返回一個(gè)AspectToken,用來(lái)注銷hook方法。所有的調(diào)用都是線程安全的。

/// Deregister an aspect.
/// @return YES if deregistration is successful, otherwise NO.
id<AspectToken> aspect = ...;
[aspect remove];

這里的AspectToken是隱式的,允許我們調(diào)用remove去撤銷一個(gè)hook。remove方法返回YES代表撤銷成功,返回NO就撤銷失敗。

Hook方法的參數(shù)

參數(shù)名 類型 含義
selector SEL 要Hook的方法,即增加切面的原方法
options AspectOptions 切入點(diǎn)
block id 這個(gè)block復(fù)制了正在被hook的方法的簽名signature類型。
error NSError ** 返回的錯(cuò)誤

block第一個(gè)參數(shù)遵循AspectInfo協(xié)議。我們甚至可以使用一個(gè)空的block。AspectInfo協(xié)議里面的參數(shù)是可選的,主要是用來(lái)匹配block簽名的。

AspectOptions類型:
typedef NS_OPTIONS(NSUInteger, AspectOptions) {
    AspectPositionAfter   = 0,            /// Called after the original implementation (default);默認(rèn)值,在原方法執(zhí)行完之后調(diào)用block
    AspectPositionInstead = 1,            /// Will replace the original implementation.替換原方法
    AspectPositionBefore  = 2,            /// Called before the original implementation.在原方法之前調(diào)用block
    
    AspectOptionAutomaticRemoval = 1 << 3 /// Will remove the hook after the first execution.在hook執(zhí)行完后自動(dòng)移除。
};
AspectInfo對(duì)象:
/// The AspectInfo protocol is the first parameter of our block syntax.
@protocol AspectInfo <NSObject>

/// The instance that is currently hooked. 
/// 返回當(dāng)前被hook的實(shí)例。
- (id)instance;

/// The original invocation of the hooked method.
/// 返回被hooked方法的原始的Invocation。
- (NSInvocation *)originalInvocation;

/// All method arguments, boxed. This is lazily evaluated.
/// 返回selector方法的所有參數(shù)。是懶加載實(shí)現(xiàn)的。
- (NSArray *)arguments;

@end
錯(cuò)誤碼類型:
typedef NS_ENUM(NSUInteger, AspectErrorCode) {
    AspectErrorSelectorBlacklisted,                   /// Selectors like release, retain, autorelease are blacklisted.
    AspectErrorDoesNotRespondToSelector,              /// Selector could not be found.
    AspectErrorSelectorDeallocPosition,               /// When hooking dealloc, only AspectPositionBefore is allowed.
    AspectErrorSelectorAlreadyHookedInClassHierarchy, /// Statically hooking the same method in subclasses is not allowed.
    AspectErrorFailedToAllocateClassPair,             /// The runtime failed creating a class pair.
    AspectErrorMissingBlockSignature,                 /// The block misses compile time signature info and can't be called.
    AspectErrorIncompatibleBlockSignature,            /// The block signature does not match the method or is too large.

    AspectErrorRemoveObjectAlreadyDeallocated = 100   /// (for removing) The object hooked is already deallocated.
};

extern NSString *const AspectErrorDomain;

.m分析TODO

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容