AOP 面向切面编程,在对于埋点、日志记录等操作来说是一个很好的解决方案。而 Aspects 是一个对于AOP编程的一个优雅的实现,也可以直接借助这个库来使用AOP思想。需要值得注意的是,Aspects 是通过消息转发机制的最后一个阶段 ForwardInvocation 来实现的,为了性能,所以这里不要频繁的调用。 github:https://github.com/steipete/Aspects
Aspects的源码学习,我学到的有几下几点
- Objective-C Runtime
- 理解OC的消息分发机制
- KVO中的指针交换技术
- Block 在内存中的数据结构
- const 的修饰区别
- block 中常量在特定情况下的三种处理方法
- 断言语句,
- 自旋锁 使用注意
_objc_msgForward_stret 和 _objc_msgForward 前者存在的必要
- Type Encoding
下面是我读源码的一些
Aspects 的接口只有两个:
/// 为一个指定的类的某个方法执行前/替换/后,添加一段代码块.对这个类的所有对象都会起作用.
///
/// @param block 方法被添加钩子时,Aspectes会拷贝方法的签名信息.
/// 第一个参数将会是 `id<AspectInfo>`,余下的参数是此被调用的方法的参数.
/// 这些参数是可选的,并将被用于传递给block代码块对应位置的参数.
/// 你甚至使用一个没有任何参数或只有一个`id<AspectInfo>`参数的block代码块.
///
/// @注意 不支持给静态方法添加钩子.
/// @return 返回一个唯一值,用于取消此钩子.
+ (id<AspectToken>)aspect_hookSelector:(SEL)selector
withOptions:(AspectOptions)options
usingBlock:(id)block
error:(NSError **)error; /// 为一个指定的对象的某个方法执行前/替换/后,添加一段代码块.只作用于当前对象.
- (id<AspectToken>)aspect_hookSelector:(SEL)selector withOptions:(AspectOptions)options usingBlock:(id)block error:(NSError **)error; - (id<AspectToken>)aspect_hookSelector:(SEL)selector withOptions:(AspectOptions)options usingBlock:(id)block error:(NSError **)error;
/// 撤销一个Aspect 钩子.
/// @return YES 撤销成功, 否则返回 NO.
id<AspectToken> aspect = ...;
[aspect remove];
AspectOptions :
typedef NS_OPTIONS(NSUInteger, AspectOptions) {
AspectPositionAfter = , /// Called after the original implementation (default)
AspectPositionInstead = , /// Will replace the original implementation.
AspectPositionBefore = , /// Called before the original implementation. AspectOptionAutomaticRemoval = << /// Will remove the hook after the first execution.
}; // 定义切片时机
定义错误信息:
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 = /// (for removing) The object hooked is already deallocated.
};
/**
修饰常指针
const int *A; //const修饰指向的对象,A可变,A指向的对象不可变
int const *A; //const修饰指向的对象,A可变,A指向的对象不可变
int *const A; //const修饰指针A, A不可变,A指向的对象可变
const int *const A;//指针A和A指向的对象都不可变 */
extern NSString *const AspectErrorDomain;
在.m 中首先是 定义了一个参与位与运算的枚举,还定义了一个block
// Block internals.
typedef NS_OPTIONS(int, AspectBlockFlags) {
AspectBlockFlagsHasCopyDisposeHelpers = ( << ),
AspectBlockFlagsHasSignature = ( << )
};
typedef struct _AspectBlock { //参考系统的block 定义了一个自己block,关于block学习 https://maniacdev.com/2013/11/tutorial-an-in-depth-guide-to-objective-c-block-debugging
__unused Class isa; // __unused 如果变量没有使用就不会参与编译,也不会报warning
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;
然后是几个类定义
AspectInfo,主要是 NSInvocation 信息。将NSInvocation包装一层,比如参数信息等。便于直接使用。
AspectIdentifier,一个Aspect的具体内容。主要包含了单个的 aspect 的具体信息,包括执行时机,要执行 block 所需要用到的具体信息:包括方法签名、参数等等。其实就是将我们传入的bloc,包装成AspectIdentifier,便于后续使用。通过我们替换的block实例化。也就是将我们传入的block,包装成了AspectIdentifier
AspectsContainer,一个对象或者类的所有的 Aspects 整体情况,注意这里数组是通过atomic修饰的。
AspectTracker,用于跟踪所改变的类,打上标记,用于替换类方法,防止重复替换类方法。
接下来定义了一个参与(切片时机)位与运算的宏
#define AspectPositionFilter 0x07 // 二进制就是111
将具体的`AspectIdentifier `添加到容器中
static id aspect_add(id self, SEL selector, AspectOptions options, id block, NSError **error) {
/**
NSCParameterAssert 针对C函数的参数断言 详情参考https://www.jianshu.com/p/6e444981ab45
NSAssert 针对OC方法的条件断言
NSCAssert 针对C函数的条件断言 NSCAssert(a == 2, @"a must equal to 2"); //第一个参数是条件,如果第一个参数不满足条件,就会记录并打印后面的字符串
NSParameterAssert 针对OC方法的参数断言 NSParameterAssert(str); //只需要一个参数,如果参数存在程序继续运行,如果参数为空,则程序停止打印日志
NSCparameterAssert 针对C函数的参数断言
*/
NSCParameterAssert(self);
NSCParameterAssert(selector);
NSCParameterAssert(block); __block AspectIdentifier *identifier = nil; //关于__block学习了 禅与Objective-C编程 https://github.com/oa414/objc-zen-book-cn/
aspect_performLocked(^{
if (aspect_isSelectorAllowedAndTrack(self, selector, options, error)) {
AspectsContainer *aspectContainer = aspect_getContainerForObject(self, selector);
identifier = [AspectIdentifier identifierWithSelector:selector object:self options:options block:block error:error];
if (identifier) {
[aspectContainer addAspect:identifier withOptions:options]; // Modify the class to allow message interception.
aspect_prepareClassAndHookSelector(self, selector, error);
}
}
});
return identifier;
}
//自旋锁,如果访问这个锁的线程不是同一优先级的话,可能会造成死锁。具体原因请看 不再安全的 OSSpinLock。
static void aspect_performLocked(dispatch_block_t block) {
static OSSpinLock aspect_lock = OS_SPINLOCK_INIT;
OSSpinLockLock(&aspect_lock);
//加锁执行block
block();
//释放锁
OSSpinLockUnlock(&aspect_lock);
}
合成selector的别名 加上@“aspects__”
static SEL aspect_aliasForSelector(SEL selector) { NSCParameterAssert(selector); return NSSelectorFromString([AspectsMessagePrefix stringByAppendingFormat:@"_%@", NSStringFromSelector(selector)]); }
具体的block内存结构定义、flags和block 中定义的枚举掩码 参考http://clang.llvm.org/docs/Block-ABI-Apple.html
将block 签名转换为方法签名
static NSMethodSignature *aspect_blockMethodSignature(id block, NSError **error) {
//// 将block转换为自定义的block形式
AspectBlockRef layout = (__bridge void *)block;
if (!(layout->flags & AspectBlockFlagsHasSignature)) {// 比对layout的第8字节到11字节的第三十位 是不是1(1就是有签名)
NSString *description = [NSString stringWithFormat:@"The block %@ doesn't contain a type signature.", block];
AspectError(AspectErrorMissingBlockSignature, description);
return nil;
}
void *desc = layout->descriptor;
desc += * sizeof(unsigned long int); //desc 地址加上16字节
if (layout->flags & AspectBlockFlagsHasCopyDisposeHelpers) {//比对layout的第8字节到11字节的第25位 是不是1(1就是有COPY_DISPOSE)
desc += * sizeof(void *); //desc 再加 8 字节,这时候的地址才是真正signature的地址
}
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 的签名
static BOOL aspect_isCompatibleBlockSignature(NSMethodSignature *blockSignature, id object, SEL selector, NSError **error) {
NSCParameterAssert(blockSignature);
NSCParameterAssert(object);
NSCParameterAssert(selector); BOOL signaturesMatch = YES;
NSMethodSignature *methodSignature = [[object class] instanceMethodSignatureForSelector:selector];
if (blockSignature.numberOfArguments > methodSignature.numberOfArguments) {
signaturesMatch = NO;
}else {
if (blockSignature.numberOfArguments > ) {
const char *blockType = [blockSignature getArgumentTypeAtIndex:];
if (blockType[] != '@') {
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.
if (signaturesMatch) {
for (NSUInteger idx = ; idx < blockSignature.numberOfArguments; idx++) {
const char *methodType = [methodSignature getArgumentTypeAtIndex:idx];
const char *blockType = [blockSignature getArgumentTypeAtIndex:idx];
// Only compare parameter, not the optional type data. 只比较参数的类型
if (!methodType || !blockType || methodType[] != blockType[]) {
signaturesMatch = NO; break;
}
}
}
} if (!signaturesMatch) {
NSString *description = [NSString stringWithFormat:@"Block signature %@ doesn't match %@.", blockSignature, methodSignature];
AspectError(AspectErrorIncompatibleBlockSignature, description);
return NO;
}
return YES;
}
手动调用消息转发
static BOOL aspect_isMsgForwardIMP(IMP impl) {
return impl == _objc_msgForward
#if !defined(__arm64__)
|| impl == (IMP)_objc_msgForward_stret
#endif
;
}
static IMP aspect_getMsgForwardIMP(NSObject *self, SEL selector) {
IMP msgForwardIMP = _objc_msgForward;
#if !defined(__arm64__) // 在 arm64 的架构上 是va_arg 的结构体 改变了, 所以针对非arm64 的结构进行了处理
// As an ugly internal runtime implementation detail in the 32bit runtime, we need to determine of the method we hook returns a struct or anything larger than id.
// https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/LowLevelABI/000-Introduction/introduction.html
// https://github.com/ReactiveCocoa/ReactiveCocoa/issues/783
// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042e/IHI0042E_aapcs.pdf (Section 5.4)
Method method = class_getInstanceMethod(self.class, selector);
const char *encoding = method_getTypeEncoding(method);
BOOL methodReturnsStructValue = encoding[] == _C_STRUCT_B;// 判断方法的类型的编码第一位是不是 _C_STRUCT_B
if (methodReturnsStructValue) {
@try {
NSUInteger valueSize = ;
NSGetSizeAndAlignment(encoding, &valueSize, NULL); if (valueSize == || valueSize == || valueSize == || valueSize == ) { // i386 架构 http://sealiesoftware.com/blog/archive/2008/10/30/objc_explain_objc_msgSend_stret.html
methodReturnsStructValue = NO;
}
} @catch (__unused NSException *e) {}
}
if (methodReturnsStructValue) {
msgForwardIMP = (IMP)_objc_msgForward_stret;
}
#endif
return msgForwardIMP;
}
以下是核心类的实现,原作者的注释已经很清晰了
static void aspect_prepareClassAndHookSelector(NSObject *self, SEL selector, NSError **error) {
NSCParameterAssert(selector);
Class klass = aspect_hookClass(self, error);
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);
SEL aliasSelector = aspect_aliasForSelector(selector);
if (![klass instancesRespondToSelector:aliasSelector]) {
__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);
} // We use forwardInvocation to hook in.
class_replaceMethod(klass, selector, aspect_getMsgForwardIMP(self, selector), typeEncoding);
AspectLog(@"Aspects: Installed hook for -[%@ %@].", klass, NSStringFromSelector(selector));
}
} // Will undo the runtime changes made.
static void aspect_cleanupHookedClassAndSelector(NSObject *self, SEL selector) {
NSCParameterAssert(self);
NSCParameterAssert(selector); Class klass = object_getClass(self);
BOOL isMetaClass = class_isMetaClass(klass);
if (isMetaClass) {
klass = (Class)self;
} // Check if the method is marked as forwarded and undo that.
Method targetMethod = class_getInstanceMethod(klass, selector);
IMP targetMethodIMP = method_getImplementation(targetMethod);
if (aspect_isMsgForwardIMP(targetMethodIMP)) {
// Restore the original method implementation.
const char *typeEncoding = method_getTypeEncoding(targetMethod);
SEL aliasSelector = aspect_aliasForSelector(selector);
Method originalMethod = class_getInstanceMethod(klass, aliasSelector);
IMP originalIMP = method_getImplementation(originalMethod);
NSCAssert(originalMethod, @"Original implementation for %@ not found %@ on %@", NSStringFromSelector(selector), NSStringFromSelector(aliasSelector), klass); class_replaceMethod(klass, selector, originalIMP, typeEncoding);
AspectLog(@"Aspects: Removed hook for -[%@ %@].", klass, NSStringFromSelector(selector));
} // Deregister global tracked selector
aspect_deregisterTrackedSelector(self, selector); // Get the aspect container and check if there are any hooks remaining. Clean up if there are not.
AspectsContainer *container = aspect_getContainerForObject(self, selector);
if (!container.hasAspects) {
// Destroy the container
aspect_destroyContainerForObject(self, selector); // Figure out how the class was modified to undo the changes.
NSString *className = NSStringFromClass(klass);
if ([className hasSuffix:AspectsSubclassSuffix]) {
Class originalClass = NSClassFromString([className stringByReplacingOccurrencesOfString:AspectsSubclassSuffix withString:@""]);
NSCAssert(originalClass != nil, @"Original class must exist");
object_setClass(self, originalClass);
AspectLog(@"Aspects: %@ has been restored.", NSStringFromClass(originalClass)); // We can only dispose the class pair if we can ensure that no instances exist using our subclass.
// Since we don't globally track this, we can't ensure this - but there's also not much overhead in keeping it around.
//objc_disposeClassPair(object.class);
}else {
// Class is most likely swizzled in place. Undo that.
if (isMetaClass) {
aspect_undoSwizzleClassInPlace((Class)self);
}else if (self.class != klass) {
aspect_undoSwizzleClassInPlace(klass);
}
}
}
}
HOOK Class 主要是 swizzling 类/对象的 forwardInvocation 函数
aspects 的真正的处理逻辑都是在 forwradInvocation 函数里面进行的。对于对象实例而言,源代码中并没有直接 swizzling 对象的 forwardInvocation 方法,而是动态生成一个当前对象的子类,并将当前对象与子类关联,然后替换子类的 forwardInvocation 方法(这里具体方法就是调用了 object_setClass(self, subclass) ,将当前对象 isa 指针指向了 subclass ,同时修改了 subclass 以及其 subclass metaclass 的 class 方法,使他返回当前对象的 class。,这个地方特别绕,它的原理有点类似 kvo 的实现,它想要实现的效果就是,将当前对象变成一个 subclass 的实例,同时对于外部使用者而言,又能把它继续当成原对象在使用,而且所有的 swizzling 操作都发生在子类,这样做的好处是你不需要去更改对象本身的类,也就是,当你在 remove aspects 的时候,如果发现当前对象的 aspect 都被移除了,那么,你可以将 isa 指针重新指回对象本身的类,从而消除了该对象的 swizzling ,同时也不会影响到其他该类的不同对象)。对于每一个对象而言,这样的动态对象只会生成一次,这里 aspect_swizzlingForwardInvocation 将使得 forwardInvocation 方法指向 aspects 自己的实现逻辑。
当前对象的子类-----isa指向----> 当前对象----isa指向---->当前类
当前对象----isa指向---->当前对象的子类----isa指向---->当前类
当remove aspects后,当前对象的isa指向当前类
static Class aspect_hookClass(NSObject *self, NSError **error) {
NSCParameterAssert(self);
/**
[self class] 返回self的类对象
object_getClass(self) 返回isa指向的类对象,
*/
Class statedClass = self.class;
Class baseClass = object_getClass(self); // isa指向的类,那如果是被KVO的属性 怎么办?
NSString *className = NSStringFromClass(baseClass); // Already subclassed 判断是否已经是添加过_Aspects_而创建的子类了,是就直接返回
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. 创建 _Aspects_ 后缀动态子类
const char *subclassName = [className stringByAppendingString:AspectsSubclassSuffix].UTF8String;
Class subclass = objc_getClass(subclassName); if (subclass == nil) {
subclass = objc_allocateClassPair(baseClass, subclassName, );
if (subclass == nil) {
NSString *errrorDesc = [NSString stringWithFormat:@"objc_allocateClassPair failed to allocate class %s.", subclassName];
AspectError(AspectErrorFailedToAllocateClassPair, errrorDesc);
return nil;
} aspect_swizzleForwardInvocation(subclass);
aspect_hookedGetClass(subclass, statedClass);
aspect_hookedGetClass(object_getClass(subclass), statedClass);
objc_registerClassPair(subclass);
} object_setClass(self, subclass);//将当前self设置为子类,这里其实只是更改了self的isa指针而已
return subclass;
}
ForwardInvocation: IMP指向__ASPECTS_ARE_BEING_CALLED__ ,再创建 __aspects_forwardInvocation:指向原来的IMP
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.
IMP originalImplementation = class_replaceMethod(klass, @selector(forwardInvocation:), (IMP)__ASPECTS_ARE_BEING_CALLED__, "v@:@");//type Encoding https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-CH100-SW1
if (originalImplementation) {
class_addMethod(klass, NSSelectorFromString(AspectsForwardInvocationSelectorName), originalImplementation, "v@:@");
}
AspectLog(@"Aspects: %@ is now aspect aware.", NSStringFromClass(klass));
}
替换子类class 方法的IMP,
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_replaceMethod(class, @selector(class), newIMP, method_getTypeEncoding(method));
}
经过Swizzle forwardInvocation 的类都保存在这里
static Class aspect_swizzleClassInPlace(Class klass) {
NSCParameterAssert(klass);
NSString *className = NSStringFromClass(klass); _aspect_modifySwizzledClasses(^(NSMutableSet *swizzledClasses) {
if (![swizzledClasses containsObject:className]) {
aspect_swizzleForwardInvocation(klass);
[swizzledClasses addObject:className];
}
});
return klass;
}
对参数进行检查是否合格
static BOOL aspect_isSelectorAllowedAndTrack(NSObject *self, SEL selector, AspectOptions options, NSError **error) {
static NSSet *disallowedSelectorList;
static dispatch_once_t pred;
dispatch_once(&pred, ^{
disallowedSelectorList = [NSSet setWithObjects:@"retain", @"release", @"autorelease", @"forwardInvocation:", nil];
}); // Check against the blacklist. 检查传进来的selector是不是黑名单中的 @"retain", @"release", @"autorelease", @"forwardInvocation:"
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;// 0x000 0x010 0x100 前三个 和0x111进行&运算,作者想要的结果是 AspectPositionBefore 0x010
if ([selectorName isEqualToString:@"dealloc"] && position != AspectPositionBefore) {
NSString *errorDesc = @"AspectPositionBefore is the only valid position when hooking dealloc.";
AspectError(AspectErrorSelectorDeallocPosition, errorDesc);
return NO;
}
//类或者对象 必须响应这个 selector
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))) {
Class klass = [self class];
NSMutableDictionary *swizzledClassesDict = aspect_getSwizzledClassesDict();
Class currentClass = [self class];
//swizzledClassesDict 仅仅是初始化了可变字典,没有存值,怎么就取值了呢
AspectTracker *tracker = swizzledClassesDict[currentClass];
if ([tracker subclassHasHookedSelectorName:selectorName]) { NSSet *subclassTracker = [tracker subclassTrackersHookingSelectorName:selectorName];
NSSet *subclassNames = [subclassTracker valueForKey:@"trackedClassName"];
NSString *errorDescription = [NSString stringWithFormat:@"Error: %@ already hooked subclasses: %@. A method can only be hooked once per class hierarchy.", selectorName, subclassNames];
AspectError(AspectErrorSelectorAlreadyHookedInClassHierarchy, errorDescription);
return NO;
} do {
tracker = swizzledClassesDict[currentClass];
if ([tracker.selectorNames containsObject:selectorName]) {
if (klass == currentClass) {
// Already modified and topmost! 一个类只能hook 一次
return YES;
}
NSString *errorDescription = [NSString stringWithFormat:@"Error: %@ already hooked in %@. A method can only be hooked once per class hierarchy.", selectorName, NSStringFromClass(currentClass)];
AspectError(AspectErrorSelectorAlreadyHookedInClassHierarchy, errorDescription);
return NO;
}
} while ((currentClass = class_getSuperclass(currentClass)));//只有当这个类为根类的时候才不会继续循环查找。 // Add the selector as being modified.
currentClass = klass;
AspectTracker *subclassTracker = nil;
do {
tracker = swizzledClassesDict[currentClass];
if (!tracker) {
tracker = [[AspectTracker alloc] initWithTrackedClass:currentClass];
swizzledClassesDict[(id<NSCopying>)currentClass] = tracker;
}
if (subclassTracker) {
[tracker addSubclassTracker:subclassTracker hookingSelectorName:selectorName];
} else {
[tracker.selectorNames addObject:selectorName];
} // All superclasses get marked as having a subclass that is modified.
subclassTracker = tracker;
}while ((currentClass = class_getSuperclass(currentClass)));
} else {
return YES;
} return YES;
}
取消已经跟踪的selector
static void aspect_deregisterTrackedSelector(id self, SEL selector) {
if (!class_isMetaClass(object_getClass(self))) return; NSMutableDictionary *swizzledClassesDict = aspect_getSwizzledClassesDict();
NSString *selectorName = NSStringFromSelector(selector);
Class currentClass = [self class];
AspectTracker *subclassTracker = nil;
do {
AspectTracker *tracker = swizzledClassesDict[currentClass];
if (subclassTracker) {
[tracker removeSubclassTracker:subclassTracker hookingSelectorName:selectorName];
} else {
[tracker.selectorNames removeObject:selectorName];
}
if (tracker.selectorNames.count == && tracker.selectorNamesToSubclassTrackers) {
[swizzledClassesDict removeObjectForKey:currentClass];
}
subclassTracker = tracker;
}while ((currentClass = class_getSuperclass(currentClass)));
}
有时间在继续研究。先留着