『iOS的第三方库』Aspects

涉及到的知识点有:消息转发TODO,Method-SwizzlingTODO,动态方法TODO,KVO(暂无),AOP等。
下载地址

概述

Aspects是一个轻量级的、支持Objective-C&Swift语言的AOP实现。可以把Aspects当做Method-SwizzlingTODO的一种应用。它允许你在每个类或每个实例已有方法中添加代码,可以设置切入点为after /instead/before等。比起常规的Method-SwizzlingTODO,Aspects会自动调用super方法,并且使用起来更加简单、方便。
Aspects利用OC的消息转发机制,hook消息。这样会有一些性能开销,因此不要把Aspects加到经常被使用的方法里面。Aspects是用来设计给View/Controller代码使用的,而不是用来hook每秒调用1000次的方法的。因此Aspects不应该被用在for循环这些方法里面,会造成很大的性能损耗。
Aspects是不支持hook 静态static方法的。

这里还有一些简介需要翻译,后续补上。TODO

使用方法

Aspects是NSObject的一个extension,只要是NSObject,都可以使用这两个方法。一个是用来hook类方法的,一个是hook实例方法的。

/// 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`, 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`.
///
/// @note Hooking static methods is not supported.
/// @return A token which allows to later deregister the aspect.
+ (id)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)aspect_hookSelector:(SEL)selector
                           withOptions:(AspectOptions)options
                            usingBlock:(id)block
                                 error:(NSError **)error;

添加Aspects后,会返回一个AspectToken,用来注销hook方法。所有的调用都是线程安全的。

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

这里的AspectToken是隐式的,允许我们调用remove去撤销一个hook。remove方法返回YES代表撤销成功,返回NO就撤销失败。

Hook方法的参数

参数名 类型 含义
selector SEL 要Hook的方法,即增加切面的原方法
options AspectOptions 切入点
block id 这个block复制了正在被hook的方法的签名signature类型。
error NSError ** 返回的错误

block第一个参数遵循AspectInfo协议。我们甚至可以使用一个空的block。AspectInfo协议里面的参数是可选的,主要是用来匹配block签名的。

AspectOptions类型:
typedef NS_OPTIONS(NSUInteger, AspectOptions) {
    AspectPositionAfter   = 0,            /// Called after the original implementation (default);默认值,在原方法执行完之后调用block
    AspectPositionInstead = 1,            /// Will replace the original implementation.替换原方法
    AspectPositionBefore  = 2,            /// Called before the original implementation.在原方法之前调用block
    
    AspectOptionAutomaticRemoval = 1 << 3 /// Will remove the hook after the first execution.在hook执行完后自动移除。
};
AspectInfo对象:
/// The AspectInfo protocol is the first parameter of our block syntax.
@protocol AspectInfo 

/// The instance that is currently hooked. 
/// 返回当前被hook的实例。
- (id)instance;

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

/// All method arguments, boxed. This is lazily evaluated.
/// 返回selector方法的所有参数。是懒加载实现的。
- (NSArray *)arguments;

@end
错误码类型:
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

你可能感兴趣的:(『iOS的第三方库』Aspects)