前一段时间看了一篇文章(字节团队出的)使用 method_swizzle
+ NSProxy
解决 App 全埋点的问题。
然后了解了一下 NSProxy
这个虚基类,发现平常开发中能使用 NSProxy
解决定时器循环引用问题、解决 OC 的多继承问题、也能让框架有更好的扩展性。
立即打开工程内的 YYWeakProxy
看了下,发现是用消息转发实现的。在我核桃大的脑袋里,对于消息转发还停留在解决 App 内方法未实现时崩溃的拦截。
立即搜索 消息转发 的用途,发现了两个好玩的框架:
- CTMediator 解决组件化问题
- Aspects 用于 iOS hook
ps: 都是老框架了,不妨碍学习。
本文就是对 Aspects 框架的学习。
1、示例 Demo :
下方示例来自 Aspects
Demo :
// ViewController.m
@interface** ViewController ()
@end
@implementation** ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIViewController *testController = [[UIImagePickerController alloc] init];
testController.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentViewController:testController animated:YES completion:NULL];
[testController aspect_hookSelector: @selector(viewWillDisappear:) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> info, BOOL animated) {
NSLog(@"Popped Hello from Aspects", [info instance]);
} error:NULL];
}
2、方法列表
/**
Aspects uses Objective-C message forwarding to hook into messages. This will create some overhead. Don't add aspects to methods that are called a lot. Aspects is meant for view/controller code that is not called a 1000 times per second.
Adding aspects returns an opaque token which can be used to deregister again. All calls are thread safe.
*/
@interface NSObject (Aspects)
/// 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;
@end
Aspects
是 NSObject
的分类,只有两个方法,一个类方法,一个实例方法,使用Demo中的代码研究实例方法的调用。
3、调用流程
描述了调用主的流程,关于销毁的流程没有列入,本文不做研究。
4、代码分析
接下来对代码分析,大部分理解在代码中都注释好了。
1、入口方法 aspect_add
static id aspect_add(id self, SEL selector, AspectOptions options, id block, NSError **error) {
NSCParameterAssert(self);
NSCParameterAssert(selector);
NSCParameterAssert(block);
__block AspectIdentifier *identifier = nil;
/// 加锁 SpinLockLock (名为自旋锁,其实iOS 7 已经改成了 os_unfair_lock 互斥锁)
aspect_performLocked(^{
if (aspect_isSelectorAllowedAndTrack(self, selector, options, error)) {
// 加载或创建 aspect 容器。
AspectsContainer *aspectContainer = aspect_getContainerForObject(self, selector);
// 创建 AspectIdentifier 对象
identifier = [AspectIdentifier identifierWithSelector:selector object:self options:options block:block error:error];
if (identifier) {
// 按 options 分类存储 AspectIdentifier 的对象
[aspectContainer addAspect:identifier withOptions:options];
// Modify the class to allow message interception.
// 修改该类以允许消息拦截。
aspect_prepareClassAndHookSelector(self, selector, error);
}
}
});
return identifier;
}
2、判断该方法是否能 hook aspect_isSelectorAllowedAndTrack
当前方法中过滤了 retain
,release
,autorelease
, forwardInvocation:
不能 hook 的方法,并且 dealloc
方法只能在销毁前 hook。
static BOOL aspect_isSelectorAllowedAndTrack(NSObject *self, SEL selector, AspectOptions options, NSError **error) {
static NSSet *disallowedSelectorList;
static dispatch_once_t pred;
dispatch_once(&pred, ^{
/// 这些方法不允许 hook
disallowedSelectorList = [NSSet setWithObjects:@"retain", @"release", @"autorelease", @"forwardInvocation:", nil];
});
// Check against the blacklist.
// 如果是前面 disallowedSelectorList 黑名单里面的方法就返回 NO,不允许 hook
NSString *selectorName = NSStringFromSelector(selector);
if ([disallowedSelectorList containsObject:selectorName]) {
NSString *errorDescription = [NSString stringWithFormat:@"Selector %@ is blacklisted.", selectorName];
AspectError(AspectErrorSelectorBlacklisted, errorDescription);
return NO;
}
// Additional checks.
// 检查 dealloc 方法只能 hook 销毁之前。
AspectOptions position = options&AspectPositionFilter;
if ([selectorName isEqualToString:@"dealloc"] && position != AspectPositionBefore) {
NSString *errorDesc = @"AspectPositionBefore is the only valid position when hooking dealloc.";
AspectError(AspectErrorSelectorDeallocPosition, errorDesc);
return NO;
}
// 检查方法时候实现,未实现不hook,没意义。
if (![self respondsToSelector:selector] && ![self.class instancesRespondToSelector:selector]) {
NSString *errorDesc = [NSString stringWithFormat:@"Unable to find selector -[%@ %@].", NSStringFromClass(self.class), selectorName];
AspectError(AspectErrorDoesNotRespondToSelector, errorDesc);
return NO;
}
// Search for the current class and the class hierarchy IF we are modifying a class object
// 如果我们正在修改类对象,则搜索当前类和类的层次结构
if (class_isMetaClass(object_getClass(self))) {
/// hook 类方法进入
Class klass = [self class];
NSMutableDictionary *swizzledClassesDict = aspect_getSwizzledClassesDict();
Class currentClass = [self class];
do {
/// 防止重复 hook
AspectTracker *tracker = swizzledClassesDict[currentClass];
if ([tracker.selectorNames containsObject:selectorName]) {
// Find the topmost class for the log.
if (tracker.parentEntry) {
AspectTracker *topmostEntry = tracker.parentEntry;
while (topmostEntry.parentEntry) {
topmostEntry = topmostEntry.parentEntry;
}
NSString *errorDescription = [NSString stringWithFormat:@"Error: %@ already hooked in %@. A method can only be hooked once per class hierarchy.", selectorName, NSStringFromClass(topmostEntry.trackedClass)];
AspectError(AspectErrorSelectorAlreadyHookedInClassHierarchy, errorDescription);
return NO;
}else if (klass == currentClass) {
// Already modified and topmost!
return YES;
}
}
}while ((currentClass = class_getSuperclass(currentClass)));
// Add the selector as being modified.
currentClass = klass;
AspectTracker *parentTracker = nil;
do {
/// 依次向父级查找,加入字典
AspectTracker *tracker = swizzledClassesDict[currentClass];
if (!tracker) {
tracker = [[AspectTracker alloc] initWithTrackedClass:currentClass parent:parentTracker];
swizzledClassesDict[(id<NSCopying>)currentClass] = tracker;
}
[tracker.selectorNames addObject:selectorName];
// All superclasses get marked as having a subclass that is modified.
parentTracker = tracker;
}while ((currentClass = class_getSuperclass(currentClass)));
}
return YES;
}
3、获取 aspect 容器 aspect_getContainerForObject
// Loads or creates the aspect container.
// 加载或创建 aspect 容器。
static AspectsContainer *aspect_getContainerForObject(NSObject *self, SEL selector) {
NSCParameterAssert(self);
// 给方法加前缀 aspects_ xx
SEL aliasSelector = aspect_aliasForSelector(selector);
/// 初始化 AspectsContainer 对象,关联到当前对象上,
AspectsContainer *aspectContainer = objc_getAssociatedObject(self, aliasSelector);
if (!aspectContainer) {
aspectContainer = [AspectsContainer new];
objc_setAssociatedObject(self, aliasSelector, aspectContainer, OBJC_ASSOCIATION_RETAIN);
}
return aspectContainer;
}
4、AspectIdentifier 初始化
这个方法里面,只需要关注 aspect_blockMethodSignature
获取 block 的方法签名。
+ (instancetype)identifierWithSelector:(SEL)selector object:(id)object options:(AspectOptions)options block:(id)block error:(NSError **)error {
NSCParameterAssert(block);
NSCParameterAssert(selector);
/// 获取 block 的方法签名
NSMethodSignature *blockSignature = aspect_blockMethodSignature(block, error); // TODO: check signature compatibility, etc.
/// 验证block 中的参数和 hook 方法的参数 是否兼容
if (!aspect_isCompatibleBlockSignature(blockSignature, object, selector, error)) {
return nil;
}
/// 构建 identifier 对象
AspectIdentifier *identifier = nil;
if (blockSignature) {
identifier = [AspectIdentifier new];
identifier.selector = selector;
identifier.block = block;
identifier.blockSignature = blockSignature;
identifier.options = options;
identifier.object = object; // weak
}
return identifier;
}
4.1 获取 block 的方法签名 aspect_blockMethodSignature
这个方法里面,重点关注第一行 AspectBlockRef layout = (__bridge void *)block;
,将 block 桥接了一下,方便取值。
桥接结构如下:
// Block internals.
typedef NS_OPTIONS(int, AspectBlockFlags) {
AspectBlockFlagsHasCopyDisposeHelpers = (1 << 25),
AspectBlockFlagsHasSignature = (1 << 30)
};
typedef struct _AspectBlock {
__unused Class isa;
AspectBlockFlags flags;
__unused int reserved;
void (__unused *invoke)(struct _AspectBlock *block, ...);
struct {
unsigned long int reserved;
unsigned long int size;
// requires AspectBlockFlagsHasCopyDisposeHelpers
void (*copy)(void *dst, const void *src);
void (*dispose)(const void *);
// requires AspectBlockFlagsHasSignature
const char *signature;
const char *layout;
} *descriptor;
// imported variables
} *AspectBlockRef;
源码实现:
/// 获取 block 的方法签名
static NSMethodSignature *aspect_blockMethodSignature(id block, NSError **error) {
// 因为block 内部构造原因能桥接 block 方便取值。
// Block 原来你是这样的(一)https://juejin.cn/post/6955409380321787940
// Block 原来你是这样的(二)https://juejin.cn/post/6956895256998576164
AspectBlockRef layout = (__bridge void *)block;
// 根据 flags 内部生成规则。判断 BlockFlagsHasSignature 如果没有 block 方法签名就返 nil
if (!(layout->flags & AspectBlockFlagsHasSignature)) {
NSString *description = [NSString stringWithFormat:@"The block %@ doesn't contain a type signature.", block];
AspectError(AspectErrorMissingBlockSignature, description);
return nil;
}
/// 取出 descriptor 结构体的首地址
void *desc = layout->descriptor;
/**
struct {
unsigned long int reserved;
unsigned long int size;
// requires AspectBlockFlagsHasCopyDisposeHelpers
void (*copy)(void *dst, const void *src);
void (*dispose)(const void *);
// requires AspectBlockFlagsHasSignature
const char *signature;
const char *layout;
} *descriptor;
*/
// 偏移过2个int 单位( 指针走过 unsigned long int reserved; 和 unsigned long int size;)
desc += 2 * sizeof(unsigned long int);
// 如果 BlockFlagsHasCopyDisposeHelpers 再偏移 2个 void * 单位 ( 指针走过 void (*copy) 和 void (*dispose))
if (layout->flags & AspectBlockFlagsHasCopyDisposeHelpers) {
desc += 2 * sizeof(void *);
}
// 当前指针指向 const char *signature;
// 如果指针地址不存在。说明 signature 不存在,就返 nil
if (!desc) {
NSString *description = [NSString stringWithFormat:@"The block %@ doesn't has a type signature.", block];
AspectError(AspectErrorMissingBlockSignature, description);
return nil;
}
// 返回 NSMethodSignature 对象
const char *signature = (*(const char **)desc);
return [NSMethodSignature signatureWithObjCTypes:signature];
}
如果不能理解是如何桥接的,可以看看这两篇文章,对 Block 内部结构的分析。
5、验证 block 中的参数和 hook 方法的参数是否兼容 aspect_isCompatibleBlockSignature
/// 验证block 中的参数和 hook 方法的参数 是否兼容
static BOOL aspect_isCompatibleBlockSignature(NSMethodSignature *blockSignature, id object, SEL selector, NSError **error) {
NSCParameterAssert(blockSignature);
NSCParameterAssert(object);
NSCParameterAssert(selector);
// 签名匹配
BOOL signaturesMatch = YES;
/// 获取需要 hook SEL 的方法签名
NSMethodSignature *methodSignature = [[object class] instanceMethodSignatureForSelector:selector];
/**
* 举例: hook 了 viewWillDisappear
* 方法 ArgumentTypeAtIndex
* 1 :self
* 2 : SEL
* 3:bool (animated)
*
* blockSignature 中 方法 ArgumentTypeAtIndex
* 1: self
* 2: AspectInfo
* 3: bool (animated)
* 如果本身 hook 的方法只有 2个 Argument 比如: dealloc (self,SEL)
* 但是,blockSignature 有 3个 Argument (self,SEL,bool)
* 如果这样 blockSignature.numberOfArguments > methodSignature.numberOfArguments 就不匹配。
* 所以 该方法 允许 blockSignature 少于 methodSignature 的 arguments (有的不使用),但是不能多于。
*/
if (blockSignature.numberOfArguments > methodSignature.numberOfArguments) {
signaturesMatch = NO;
}else {
if (blockSignature.numberOfArguments > 1) {
/// 这里需要强制 第二个参数 是 AspectInfo
const char *blockType = [blockSignature getArgumentTypeAtIndex:1];
if (blockType[0] != '@') {
signaturesMatch = NO;
}
}
// Argument 0 is self/block, argument 1 is SEL or id<AspectInfo>. We start comparing at argument 2.
// The block can have less arguments than the method, that's ok.
// 参数0是self/block,参数1是SEL或id。我们从 index = 2 开始比较。
// block的参数可以比方法少,这是可以的。
if (signaturesMatch) {
for (NSUInteger idx = 2; idx < blockSignature.numberOfArguments; idx++) {
const char *methodType = [methodSignature getArgumentTypeAtIndex:idx];
const char *blockType = [blockSignature getArgumentTypeAtIndex:idx];
// Only compare parameter, not the optional type data.
// 这里允许 blockSignature 少,但是不允许跳过参数,
// 比如:hook 方法总共 4个参数 (self,SEL,Bool,Int)
// block 可以 (self,SEL,Bool)不能 (self,SEL,Int)
if (!methodType || !blockType || methodType[0] != blockType[0]) {
signaturesMatch = NO;
break;
}
}
}
}
/// 如果不匹配打印错误 返回 No
if (!signaturesMatch) {
NSString *description = [NSString stringWithFormat:@"Blog signature %@ doesn't match %@.", blockSignature, methodSignature];
AspectError(AspectErrorIncompatibleBlockSignature, description);
return NO;
}
return YES;
}
看到这里 NSMethodSignature *methodSignature = [[object class] instanceMethodSignatureForSelector:selector];
获取需要 hook SEL 的方法签名的时候发现,使用的是 instanceMethodSignatureForSelector
,所以在需要 hook 类方法的时候,就需要传入 class.metaClass
。
6、修改类以允许消息拦截 aspect_prepareClassAndHookSelector
这个方法是核心方法,使用 isa_swizzle
来实现的。
灵魂画手,不要介意哈。
简单介绍一下流程:
有一个类 MyClass
派生出一个对象 myObj
,现在需要 hook helloMethod
方法。
- Aspect 框架通过
aspect_hookClass
方法生成一个MyClass
的子类MyClass_Aspect_
- 将
myObj
的isa
指向MyClass_Aspect_
- 获取
MyClass
helloMethod
方法的IMP
- 给
MyClass_Aspect_
中添加方法aspect_helloMethod
方法,并将IMP
指向helloMethod
方法的IMP
(其实就复制了helloMethod
方法实现) - 替换或添加
MyClass_Aspect_
类中方法列表的forwardInvcation
,让其IMP
指向 Aspect 框架自己实现的__ASPECTS_ARE_BEING_CALLED__
自己处理方法转发 - 替换或添加
MyClass_Aspect_
类中方法列表的helloMethod
方法,让其IMP
指向_objc_msgForward
这样调用 MyClass
派生出对象 myObj
的实例方法 helloMethod
的时候其实就是在调用 MyClass_Aspect_
中的 helloMethod
方法。
但是 helloMethod
方法的 IMP
是 _objc_msgForward
(消息转发)就会调用 Aspect 框架自己实现的 IMP __ASPECTS_ARE_BEING_CALLED__
。
/// 准备类和 hook selector
static void aspect_prepareClassAndHookSelector(NSObject *self, SEL selector, NSError **error) {
NSCParameterAssert(selector);
Class klass = aspect_hookClass(self, error);
/// klass 是 原来类的子类。所以能获取到 父类的方法
Method targetMethod = class_getInstanceMethod(klass, selector);
///获取方法实现
IMP targetMethodIMP = method_getImplementation(targetMethod);
if (!aspect_isMsgForwardIMP(targetMethodIMP)) {
// Make a method alias for the existing method implementation, it not already copied.
const char *typeEncoding = method_getTypeEncoding(targetMethod);
/// 给方法增加前缀 AspectsMessagePrefix_
SEL aliasSelector = aspect_aliasForSelector(selector);
/// 如果新的类 klass 没有实现 aliasSelector
if (![klass instancesRespondToSelector:aliasSelector]) {
/// klass 类里面加入了 AspectsMessagePrefix_xxx 复制了 xxx 的实现
__unused BOOL addedAlias = class_addMethod(klass, aliasSelector, method_getImplementation(targetMethod), typeEncoding);
NSCAssert(addedAlias, @"Original implementation for %@ is already copied to %@ on %@", NSStringFromSelector(selector), NSStringFromSelector(aliasSelector), klass);
}
/**
* 到这里 klass (Class_Aspects_)里面方法如下:
* aspects__viewWillDisappear (在 aspect_prepareClassAndHookSelector .class_addMethod 处添加)
* class (在 aspect_hookedGetClass 处添加)
* forwardInvocation (在 aspect_hookClass -> aspect_swizzleForwardInvocation 处添加)
*/
// We use forwardInvocation to hook in.
// 给子类添加 原始 selector 方法,让其IMP指向 _objc_msgForward(消息转发)
class_replaceMethod(klass, selector, aspect_getMsgForwardIMP(self, selector), typeEncoding);
AspectLog(@"Aspects: Installed hook for -[%@ %@].", klass, NSStringFromSelector(selector));
/**
* 到这里 klass (Class_Aspects_)里面方法如下:
* viewWillDisappear: IMP -> _objc_msgForward
* aspects__viewWillDisappear: imp -> viewWillDisappear
* class IMP -> 原始类的cls
* forwardInvocation: IMP -> __ASPECTS_ARE_BEING_CALLED__
*/
}
}
6.1 动态生成一个子类 aspect_hookClass
static Class aspect_hookClass(NSObject *self, NSError **error) {
NSCParameterAssert(self);
/// object_getClass 是取 isa 也就是self 是对象时,取对象的类,如果是类时,取元类
/// class self为对象取类,如果self 是类,返回自己。
/// 如果self 是对象,那么 statedClass == baseClass
Class statedClass = self.class;
Class baseClass = object_getClass(self);
NSString *className = NSStringFromClass(baseClass);
// Already subclassed
if ([className hasSuffix:AspectsSubclassSuffix]) {
return baseClass;
// We swizzle a class object, not a single object.
// 我们混合了一个类对象,而不是单个对象。
} else if (class_isMetaClass(baseClass)) {
return aspect_swizzleClassInPlace((Class)self);
// Probably a KVO'ed class. Swizzle in place. Also swizzle meta classes in place.
} else if (statedClass != baseClass) {
return aspect_swizzleClassInPlace(baseClass);
}
// Default case. Create dynamic subclass.
const char *subclassName = [className stringByAppendingString:AspectsSubclassSuffix].UTF8String;
Class subclass = objc_getClass(subclassName);
if (subclass == nil) {
// 动态创建一个类
subclass = objc_allocateClassPair(baseClass, subclassName, 0);
if (subclass == nil) {
// 创建失败了,返回空
NSString *errrorDesc = [NSString stringWithFormat:@"objc_allocateClassPair failed to allocate class %s.", subclassName];
AspectError(AspectErrorFailedToAllocateClassPair, errrorDesc);
return nil;
}
// 添加 forwardInvocation 方法
aspect_swizzleForwardInvocation(subclass);
/**
* object_getClass是获取isa,其实object_getClass(obj)与[obj class]的区别了,就两点:
* 1、如果是obj实例对象,他们一样;
* 2、如果是类对象,class是self,object_getClass是isa
*/
/// 类派生的对象获取类对象,
aspect_hookedGetClass(subclass, statedClass);
// 防止是元类派生的类对象获取元类对象
aspect_hookedGetClass(object_getClass(subclass), statedClass);
/// 动态注册类
objc_registerClassPair(subclass);
}
/// 修改isa指针 指向我们的子类 subclass
object_setClass(self, subclass);
return subclass;
}
6.2 添加 forwardInvocation 方法 aspect_swizzleForwardInvocation
static NSString *const AspectsForwardInvocationSelectorName = @"__aspects_forwardInvocation:";
static void aspect_swizzleForwardInvocation(Class klass) {
NSCParameterAssert(klass);
// If there is no method, replace will act like class_addMethod.
// 如果没有方法,replace将扮演类似class_addMethod的角色。
// class_replaceMethod: 存在要替换的方法则替换原方法的IMP并返回原方法的IMP,,不存在原有方法则动态添加该方法并且返回nil
// 如果实现了 forwardInvocation 会把 forwardInvocation 的IMP 替换成 __ASPECTS_ARE_BEING_CALLED__
// 如果没有实现,直接添加一个forwardInvocation IMP 指向__ASPECTS_ARE_BEING_CALLED__
IMP originalImplementation = class_replaceMethod(klass, @selector(forwardInvocation:), (IMP)__ASPECTS_ARE_BEING_CALLED__, "v@:@");
// 判断是否实现了 forwardInvocation
if (originalImplementation) {
// 实现了 forwardInvocation ,需要添加一个 __aspects_forwardInvocation 方法,
class_addMethod(klass, NSSelectorFromString(AspectsForwardInvocationSelectorName), originalImplementation, "v@:@");
}
AspectLog(@"Aspects: %@ is now aspect aware.", NSStringFromClass(klass));
}
6.3 更改 @selector(class) 返回的类 aspect_hookedGetClass
这个方法在iOS框架 KVO 中用过,派生了一个子类用于键值监听,但是调用 class
方法和 objc_getClass()
方法返回是不一样的。
static void aspect_hookedGetClass(Class class, Class statedClass) {
NSCParameterAssert(class);
NSCParameterAssert(statedClass);
Method method = class_getInstanceMethod(class, @selector(class));
IMP newIMP = imp_implementationWithBlock(^(id self) {
return statedClass;
});
/// 添加 class 方法 并且返回之前的的类名
class_replaceMethod(class, @selector(class), newIMP, method_getTypeEncoding(method));
}
7、Aspects 自己的消息转发 ASPECTS_ARE_BEING_CALLED
这个方法就是拿到对象消息转发了,先处理 Before hooks
调用 block,然后如果有方法替换,处理 Instead hooks.
如果没有方法替换,就循环向父类找调用方法,最后处理 After hooks
,处理完销毁 hook。
// This is the swizzled forwardInvocation: method.
static void __ASPECTS_ARE_BEING_CALLED__(__unsafe_unretained NSObject *self, SEL selector, NSInvocation *invocation) {
NSCParameterAssert(self);
NSCParameterAssert(invocation);
SEL originalSelector = invocation.selector;
SEL aliasSelector = aspect_aliasForSelector(invocation.selector);
invocation.selector = aliasSelector;
/// 处理对象的 hook
AspectsContainer *objectContainer = objc_getAssociatedObject(self, aliasSelector);
/// 处理类的 hook
AspectsContainer *classContainer = aspect_getContainerForClass(object_getClass(self), aliasSelector);
AspectInfo *info = [[AspectInfo alloc] initWithInstance:self invocation:invocation];
NSArray *aspectsToRemove = nil;
// Before hooks.
aspect_invoke(classContainer.beforeAspects, info);
aspect_invoke(objectContainer.beforeAspects, info);
// Instead hooks.
BOOL respondsToAlias = YES;
if (objectContainer.insteadAspects.count || classContainer.insteadAspects.count) {
aspect_invoke(classContainer.insteadAspects, info);
aspect_invoke(objectContainer.insteadAspects, info);
}else {
/// 如果没有替换方法就调用原始方法
Class klass = object_getClass(invocation.target);
do {
if ((respondsToAlias = [klass instancesRespondToSelector:aliasSelector])) {
[invocation invoke];
break;
}
}while (!respondsToAlias && (klass = class_getSuperclass(klass)));
}
// After hooks.
aspect_invoke(classContainer.afterAspects, info);
aspect_invoke(objectContainer.afterAspects, info);
// If no hooks are installed, call original implementation (usually to throw an exception)
if (!respondsToAlias) {
invocation.selector = originalSelector;
SEL originalForwardInvocationSEL = NSSelectorFromString(AspectsForwardInvocationSelectorName);
if ([self respondsToSelector:originalForwardInvocationSEL]) {
((void( *)(id, SEL, NSInvocation *))objc_msgSend)(self, originalForwardInvocationSEL, invocation);
}else {
[self doesNotRecognizeSelector:invocation.selector];
}
}
// Remove any hooks that are queued for deregistration.
[aspectsToRemove makeObjectsPerformSelector:@selector(remove)];
}
5、结语
Aspects分析到这里就结束了,本文只对 Aspects 添加 hook 流程进行了分析,没有列出 Aspects 的销毁过程分析,有兴趣可以下载源码看下。
最后 2022 年 元旦,祝大家节日快乐。