美文网首页第三方库
Runtime最佳实践之Aspects

Runtime最佳实践之Aspects

作者: 蝴蝶之梦天使 | 来源:发表于2021-02-06 17:58 被阅读0次
    来之网络

    闯荡开发那些街
    有谁不识Runtime
    但却只闻黑魔法
    从未项目运乾坤

    一、前言

    使用Objective-C开发iOS项目,一定听多了Runtime也用了很多采用黑魔法的第三方库。比如

    1.Aspects(AOP必备,“取缔” baseVC,无侵入埋点)
    2.MJExtension(JSON 转 model,一行代码实现 NSCoding 协议的自动归档和解档)
    3.JSPatch(动态下发 JS 进行热修复)
    4.NullSafe(防止因发 unrecognised messages 给 NSNull 导致的崩溃)
    5.UITableView-FDTemplateLayoutCell(自动计算并缓存 table view 的 cell 高度)
    6.UINavigationController+FDFullscreenPopGesture(全屏滑动返回)

    也一定知道runtime的消息转发机制

    1.Method resolution 方法解析处理阶段:+(BOOL)resolveInstanceMethod:(SEL)sel 和 +(BOOL)resolveClassMethod:(SEL)sel。 如果没有找到,可以通过新添加一个方法并返回此方法类避免崩溃。
    2.Fast forwarding 快速转发阶段: -(id)forwardingTargetForSelector:(SEL)aSelector。 如果没有找到,则可以通过返回一个自定义的类。
    3.Normal forwarding 常规转发阶段:(1)-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector 对象根据SEL自动创建签名 (2)-(void)forwardInvocation:(NSInvocation *)anInvocation 消息转发。
    但是仅仅知道了理论知识,没有实践下,那么体会不到黑魔法的真正作用。

    二、AOP

    当听说AOP的时候感觉还挺新鲜,但是了解到实现的技术后,发现已经是“老情人”了。突然让我感觉到Runtime真的是可以做甚多事,很是激动。也明白OC的高级能力需要通过C语言来加持,即C语言学的透那么OC学的就深。(刷LeetCode用C语言吧)
    兴趣来了去看看Aspects的源码吧,将自己的不足处补补,不然我的水桶盛水有点浅。😿😿😿

    三、Aspects

    Aspects虽然已经5、6年没有更新了,里面的代码有一点快要腐败的味道(如OSSpinLock已经不是线程完全了),但是菜还是一道好菜,吃起来蛮香的。
    写一个demo试试

    #import <Aspects.h>
    

    采用pod 'Aspects', '~> 1.4.1'集成后,引用头文件。

    [self aspect_hookSelector:@selector(justTest) withOptions:AspectPositionBefore usingBlock:^(id<AspectInfo> info) {
            NSLog(@"Hello World!");
        } error:nil];
    

    将添加钩子的方法添加到类中,需要在调用justTest方法之前。

    - (void)justTest
    {
        NSLog(@"wyn 222");
    }
    

    原来的justTest方法。
    运行后打印

    MyDream[12617:504544] Hello World!
    MyDream[12617:504544] wyn 222
    

    通过AspectOptions还可以设置加载在原方法的前面,替换还是后面。

    四、Aspects关系图

    看了源码后整理下类的关系图


    Aspects类关系图

    采用的都是私有内部类。

    五、 Aspects思路

    1. 通过aspect_add方法作为入口。
    2. 在线程安全中,判断selector是否可以进行钩子。
    3. 为一个selector方法新建一个容器AspectsContainer。容器通过关联对象绑定到self中。
    4. 并且一个selector可以添加多次,如在执行前,替换和执行后。
    5. 创建切面识别AspectIdentifier,丛中包含了主入口的所有参数。
    6. 在容器中根据AspectOptions添加切面识别。
    7. 然后像KVO一样创建一个子类,替换_objc_msgForward__ASPECTS_ARE_BEING_CALLED__;
    8. 移除切面的函数为AspectToken的- (BOOL)remove;

    六、 Aspects注释

    所有方法都加了注释,可以通过注释明白都是在处理什么。碰到不清楚用法的地方,可以问问度娘。
    Aspects.h

    #import <Foundation/Foundation.h>
    
    // 用来表示加载在原方法的前面,替换还是,后面。
    typedef NS_OPTIONS(NSUInteger, AspectOptions) {
        AspectPositionAfter   = 0,            /// Called after the original implementation (default)
        AspectPositionInstead = 1,            /// Will replace the original implementation.
        AspectPositionBefore  = 2,            /// Called before the original implementation.
        
        AspectOptionAutomaticRemoval = 1 << 3 /// Will remove the hook after the first execution.
    };
    
    // 添加一个钩子方法时,返回一个token对象,用来删除钩子。
    /// Opaque Aspect Token that allows to deregister the hook.
    @protocol AspectToken <NSObject>
    
    // 直接调用删除就可以将钩子方法从之前的注册集合中删除。
    /// Deregisters an aspect.
    /// @return YES if deregistration is successful, otherwise NO.
    - (BOOL)remove;
    
    @end
    
    // 保存着注册时传入的参数内容
    /// The AspectInfo protocol is the first parameter of our block syntax.
    @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
    
    /**
     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
    
    // 错误代码
    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;
    

    Aspects.m

    #import "Aspects.h"
    #import <libkern/OSAtomic.h>
    #import <objc/runtime.h>
    #import <objc/message.h>
    
    #define AspectLog(...)
    //#define AspectLog(...) do { NSLog(__VA_ARGS__); }while(0)
    #define AspectLogError(...) do { NSLog(__VA_ARGS__); }while(0)
    
    // Block internals.
    typedef NS_OPTIONS(int, AspectBlockFlags) {
        AspectBlockFlagsHasCopyDisposeHelpers = (1 << 25),
        AspectBlockFlagsHasSignature          = (1 << 30)
    };
    // 作用是将传入的OC类对象的block,转化为C语言结构体,方法获取内容来生成实例签名。
    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;
    
    // 切面信息,保存了原来的实例,参数,原来的调用。
    // 在forwardInvocation的时候用到
    @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
    
    // 切面标识,将所有的入参包装成一个Identifier,并且添加了一个block的签名。
    // Tracks a single aspect.
    @interface AspectIdentifier : NSObject
    + (instancetype)identifierWithSelector:(SEL)selector object:(id)object options:(AspectOptions)options block:(id)block error:(NSError **)error;
    - (BOOL)invokeWithInfo:(id<AspectInfo>)info;
    @property (nonatomic, assign) SEL selector;
    @property (nonatomic, strong) id block;
    @property (nonatomic, strong) NSMethodSignature *blockSignature;
    @property (nonatomic, weak) id object;
    @property (nonatomic, assign) AspectOptions options;
    @end
    
    // 一个selector对应一个容器。容器中主要用来保存切面的标识。
    // Tracks all aspects for an object/class.
    @interface AspectsContainer : NSObject
    - (void)addAspect:(AspectIdentifier *)aspect withOptions:(AspectOptions)injectPosition;
    - (BOOL)removeAspect:(id)aspect;
    - (BOOL)hasAspects;
    @property (atomic, copy) NSArray *beforeAspects;
    @property (atomic, copy) NSArray *insteadAspects;
    @property (atomic, copy) NSArray *afterAspects;
    @end
    
    // 记录根据class对应的selector,并且会记录父类关系,用来判断是否在父类或子类中已经对selector进行hook。
    @interface AspectTracker : NSObject
    - (id)initWithTrackedClass:(Class)trackedClass parent:(AspectTracker *)parent;
    @property (nonatomic, strong) Class trackedClass;
    @property (nonatomic, strong) NSMutableSet *selectorNames;
    @property (nonatomic, weak) AspectTracker *parentEntry;
    @end
    
    // NSInvotion为消息调用类,包含target,selector,参数和返回值。
    @interface NSInvocation (Aspects)
    - (NSArray *)aspects_arguments;
    @end
    
    #define AspectPositionFilter 0x07
    
    #define AspectError(errorCode, errorDescription) do { \
    AspectLogError(@"Aspects: %@", errorDescription); \
    if (error) { *error = [NSError errorWithDomain:AspectErrorDomain code:errorCode userInfo:@{NSLocalizedDescriptionKey: errorDescription}]; }}while(0)
    
    NSString *const AspectErrorDomain = @"AspectErrorDomain";
    static NSString *const AspectsSubclassSuffix = @"_Aspects_";
    static NSString *const AspectsMessagePrefix = @"aspects_";
    
    @implementation NSObject (Aspects)
    
    ///////////////////////////////////////////////////////////////////////////////////////////
    #pragma mark - Public Aspects API
    // 提供的唯二方法,用来注册方法。  之后的事件根据事件的调用来触发。
    // block的第一个参数为aspectInfo,接下去的参数为selector的参数.
    // 可以对selector进行添加多次,并且一直会在之前的基础上新增替换。
    + (id<AspectToken>)aspect_hookSelector:(SEL)selector
                          withOptions:(AspectOptions)options
                           usingBlock:(id)block
                                error:(NSError **)error {
        return aspect_add((id)self, selector, options, block, error);
    }
    
    /// @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 {
        return aspect_add(self, selector, options, block, error);
    }
    
    ///////////////////////////////////////////////////////////////////////////////////////////
    #pragma mark - Private Helper
    
    // 主入口
    static id aspect_add(id self, SEL selector, AspectOptions options, id block, NSError **error) {
        NSCParameterAssert(self);
        NSCParameterAssert(selector);
        NSCParameterAssert(block);
    
        __block AspectIdentifier *identifier = nil;
        // 通过安全锁来确保多线程的安全
        aspect_performLocked(^{
            // 判断是否可以使用黑魔法。 有些方法是不能使用这个功能的。
            if (aspect_isSelectorAllowedAndTrack(self, selector, options, error)) {
                // 通过关联对象添加属性.一个selector方法对应一个容器。
                // 就是说,一个selector可以添加多次,执行前,替换和执行后。
                AspectsContainer *aspectContainer = aspect_getContainerForObject(self, selector);
                // 创建切面的识别,这个包含了注册的所有内容,包括需要监听或替换的selector,更换为实现的方法block
                identifier = [AspectIdentifier identifierWithSelector:selector object:self options:options block:block error:error];
                if (identifier) {
                    // 在容器中添加需要事件
                    [aspectContainer addAspect:identifier withOptions:options];
    
                    // 准备拦截selector,为了实现子类在调用selector的时候触发消息转发,从而来调用别名的实现。
                    // Modify the class to allow message interception.
                    aspect_prepareClassAndHookSelector(self, selector, error);
                }
            }
        });
        return identifier;
    }
    
    // 清除注册的方法。通过token的remove来执行。
    static BOOL aspect_remove(AspectIdentifier *aspect, NSError **error) {
        NSCAssert([aspect isKindOfClass:AspectIdentifier.class], @"Must have correct type.");
    
        __block BOOL success = NO;
        // 线性安全
        aspect_performLocked(^{
            // 局部作用域强引用,避免在作用域中被提前释放
            id self = aspect.object; // strongify
            if (self) {
                AspectsContainer *aspectContainer = aspect_getContainerForObject(self, aspect.selector);
                success = [aspectContainer removeAspect:aspect];
    
                aspect_cleanupHookedClassAndSelector(self, aspect.selector);
                // destroy token
                aspect.object = nil;
                aspect.block = nil;
                aspect.selector = NULL;
            }else {
                NSString *errrorDesc = [NSString stringWithFormat:@"Unable to deregister hook. Object already deallocated: %@", aspect];
                AspectError(AspectErrorRemoveObjectAlreadyDeallocated, errrorDesc);
            }
        });
        return success;
    }
    
    // 确保线性安全,采用了自旋锁
    static void aspect_performLocked(dispatch_block_t block) {
        static OSSpinLock aspect_lock = OS_SPINLOCK_INIT;
        OSSpinLockLock(&aspect_lock);
        block();
        OSSpinLockUnlock(&aspect_lock);
    }
    
    // 将selector设置一个别名
    static SEL aspect_aliasForSelector(SEL selector) {
        NSCParameterAssert(selector);
        return NSSelectorFromString([AspectsMessagePrefix stringByAppendingFormat:@"_%@", NSStringFromSelector(selector)]);
    }
    
    // 把block创建一个方法签名
    static NSMethodSignature *aspect_blockMethodSignature(id block, NSError **error) {
        // 通过使用__bridge将id指针转化为void *,即OC转化为C的用法
        AspectBlockRef layout = (__bridge void *)block;
        if (!(layout->flags & AspectBlockFlagsHasSignature)) {
            NSString *description = [NSString stringWithFormat:@"The block %@ doesn't contain a type signature.", block];
            AspectError(AspectErrorMissingBlockSignature, description);
            return nil;
        }
        void *desc = layout->descriptor;
        desc += 2 * sizeof(unsigned long int);
        if (layout->flags & AspectBlockFlagsHasCopyDisposeHelpers) {
            desc += 2 * sizeof(void *);
        }
        if (!desc) {
            NSString *description = [NSString stringWithFormat:@"The block %@ doesn't has a type signature.", block];
            AspectError(AspectErrorMissingBlockSignature, description);
            return nil;
        }
        const char *signature = (*(const char **)desc);
        return [NSMethodSignature signatureWithObjCTypes:signature];
    }
    
    // block生成的签名和selector生成的签名进行判断,看是否匹配。
    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 > 1) {
                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.
            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.
                    if (!methodType || !blockType || methodType[0] != blockType[0]) {
                        signaturesMatch = NO;
                        break;
                    }
                }
            }
        }
    
        if (!signaturesMatch) {
            NSString *description = [NSString stringWithFormat:@"Blog signature %@ doesn't match %@.", blockSignature, methodSignature];
            AspectError(AspectErrorIncompatibleBlockSignature, description);
            return NO;
        }
        return YES;
    }
    
    ///////////////////////////////////////////////////////////////////////////////////////////
    #pragma mark - Class + Selector Preparation
    
    // 判断impl是否是消息转发
    static BOOL aspect_isMsgForwardIMP(IMP impl) {
        return impl == _objc_msgForward
    #if !defined(__arm64__)
        || impl == (IMP)_objc_msgForward_stret
    #endif
        ;
    }
    
    // 获取_objc_msgForward的方法。 针对32位手机做了特殊处理。 32位手机包括iPhone4,4s,5,5c。从iPhone5s开始都是64位设备。
    static IMP aspect_getMsgForwardIMP(NSObject *self, SEL selector) {
        IMP msgForwardIMP = _objc_msgForward;
    #if !defined(__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[0] == _C_STRUCT_B;
        if (methodReturnsStructValue) {
            @try {
                NSUInteger valueSize = 0;
                NSGetSizeAndAlignment(encoding, &valueSize, NULL);
    
                if (valueSize == 1 || valueSize == 2 || valueSize == 4 || valueSize == 8) {
                    methodReturnsStructValue = NO;
                }
            } @catch (NSException *e) {}
        }
        if (methodReturnsStructValue) {
            msgForwardIMP = (IMP)_objc_msgForward_stret;
        }
    #endif
        return msgForwardIMP;
    }
    
    // 准备拦截selector:创建一个子类,针对selector创建一个别名,然后将selector替换为消息转发
    static void aspect_prepareClassAndHookSelector(NSObject *self, SEL selector, NSError **error) {
        NSCParameterAssert(selector);
        // 根据当前的类创建一个类,并且替换子类的class方法,然后返回子类
        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);
            // 获取selector的别名
            SEL aliasSelector = aspect_aliasForSelector(selector);
            // 在已开始注册selector的时候,通过aspect_getContainerForObject对selector创建给一个容器。容器中保存了钩子的selector,并根据执行前后,会依次执行。
            // 不类不响应这个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);
            }
    
            // 使用_objc_msgForward替换了类的selector
            // 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);
        // selector方法是_objc_msgForward,则将方法再还回来。
        // 即注册的时候将forwardInvocation替换为__aspects_forwardInvocation:,也就是系统调用forwardInvocation时执行的是__aspects_forwardInvocation:,
        // 现在将forwardInvocation和__aspects_forwardInvocation再替换一次。
        if (aspect_isMsgForwardIMP(targetMethodIMP)) {
            // Restore the original method implementation.
            const char *typeEncoding = method_getTypeEncoding(targetMethod);
            // selector的别名。容器中保存的都是别名的。
            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));
        }
    
        // 删除selector在全局中切面痕迹
        // Deregister global tracked selector
        aspect_deregisterTrackedSelector(self, selector);
    
        // 根据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);
                }
            }
        }
    }
    
    ///////////////////////////////////////////////////////////////////////////////////////////
    #pragma mark - Hook Class
    
    // 根据当前的类创建一个类,并且替换子类的class方法,然后返回子类
    static Class aspect_hookClass(NSObject *self, NSError **error) {
        NSCParameterAssert(self);
        // 获取的当前的类
        Class statedClass = self.class;
        Class baseClass = object_getClass(self);
        NSString *className = NSStringFromClass(baseClass);
    
        // 已经是aspect的方法了
        // 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) {
            // 类不同,就进行替换。使用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);
            // 重写subclass的class方法,返回statedClass的class方法
            aspect_hookedGetClass(subclass, statedClass);
            // 重写subclass的class方法,返回statedClass的class方法
            // object_getClass 返回的子类的运行时类
            aspect_hookedGetClass(object_getClass(subclass), statedClass);
            // 注册动态创建的子类
            objc_registerClassPair(subclass);
        }
    
        // 修改当前的类为动态生成的子类。
        object_setClass(self, subclass);
        
        return subclass;
    }
    
    // 替换forwardInvocation方法
    static NSString *const AspectsForwardInvocationSelectorName = @"__aspects_forwardInvocation:";
    static void aspect_swizzleForwardInvocation(Class klass) {
        NSCParameterAssert(klass);
        // 把forwardInvocation方法的实现替换
        // If there is no method, replace will act like class_addMethod.
        IMP originalImplementation = class_replaceMethod(klass, @selector(forwardInvocation:), (IMP)__ASPECTS_ARE_BEING_CALLED__, "v@:@");
        if (originalImplementation) {
            // 给class添加特定的方法,和已经替换forwardInvocation后的实现
            class_addMethod(klass, NSSelectorFromString(AspectsForwardInvocationSelectorName), originalImplementation, "v@:@");
        }
        AspectLog(@"Aspects: %@ is now aspect aware.", NSStringFromClass(klass));
    }
    
    // 将__aspects_forwardInvocation替换为forwardInvocation
    static void aspect_undoSwizzleForwardInvocation(Class klass) {
        NSCParameterAssert(klass);
        Method originalMethod = class_getInstanceMethod(klass, NSSelectorFromString(AspectsForwardInvocationSelectorName));
        Method objectMethod = class_getInstanceMethod(NSObject.class, @selector(forwardInvocation:));
        // There is no class_removeMethod, so the best we can do is to retore the original implementation, or use a dummy.
        IMP originalImplementation = method_getImplementation(originalMethod ?: objectMethod);
        class_replaceMethod(klass, @selector(forwardInvocation:), originalImplementation, "v@:@");
    
        AspectLog(@"Aspects: %@ has been restored.", NSStringFromClass(klass));
    }
    
    // 模仿KVO重写了class实例方法,将子类的class方法返回原类的class。
    // class是新创建的子类; statedClass 是原本的类
    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中的@selector(class)用newIMP替换
        class_replaceMethod(class, @selector(class), newIMP, method_getTypeEncoding(method));
    }
    
    ///////////////////////////////////////////////////////////////////////////////////////////
    #pragma mark - Swizzle Class In Place
    
    // 单例创建一个swizzledClasses
    static void _aspect_modifySwizzledClasses(void (^block)(NSMutableSet *swizzledClasses)) {
        static NSMutableSet *swizzledClasses;
        static dispatch_once_t pred;
        dispatch_once(&pred, ^{
            swizzledClasses = [NSMutableSet new];
        });
        @synchronized(swizzledClasses) {
            block(swizzledClasses);
        }
    }
    
    // 把类的forwardInvocation方法替换了
    static Class aspect_swizzleClassInPlace(Class klass) {
        NSCParameterAssert(klass);
        NSString *className = NSStringFromClass(klass);
    
        _aspect_modifySwizzledClasses(^(NSMutableSet *swizzledClasses) {
            // 判断单例swizzledClasses中是否包含,如果不包含就添加
            if (![swizzledClasses containsObject:className]) {
                // 给类添加一个指定的方法和替换forwardInvocation的实现
                aspect_swizzleForwardInvocation(klass);
                [swizzledClasses addObject:className];
            }
        });
        return klass;
    }
    
    // 从全局容器中删除类对应的容器
    static void aspect_undoSwizzleClassInPlace(Class klass) {
        NSCParameterAssert(klass);
        NSString *className = NSStringFromClass(klass);
    
        _aspect_modifySwizzledClasses(^(NSMutableSet *swizzledClasses) {
            if ([swizzledClasses containsObject:className]) {
                aspect_undoSwizzleForwardInvocation(klass);
                [swizzledClasses removeObject:className];
            }
        });
    }
    
    ///////////////////////////////////////////////////////////////////////////////////////////
    #pragma mark - Aspect Invoke Point
    
    // invocation开始调用
    // This is a macro so we get a cleaner stack trace.
    #define aspect_invoke(aspects, info) \
    for (AspectIdentifier *aspect in aspects) {\
        [aspect invokeWithInfo:info];\
        if (aspect.options & AspectOptionAutomaticRemoval) { \
            aspectsToRemove = [aspectsToRemove?:@[] arrayByAddingObject:aspect]; \
        } \
    }
    
    // 替换forwardInvocation方法,实现了自定义的forwardInvocation方法
    // 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;
        AspectsContainer *objectContainer = objc_getAssociatedObject(self, aliasSelector);
        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;
            // 调用__aspects_forwardInvocation:方法,因为已经替换了,所以调用的是之前的旧的方法
            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)];
    }
    #undef aspect_invoke
    
    ///////////////////////////////////////////////////////////////////////////////////////////
    #pragma mark - Aspect Container Management
    
    // 加载或创建容器。 通过关联对象添加属性.一个selector方法对应一个容器。
    // Loads or creates the aspect container.
    static AspectsContainer *aspect_getContainerForObject(NSObject *self, SEL selector) {
        NSCParameterAssert(self);
        SEL aliasSelector = aspect_aliasForSelector(selector);
        AspectsContainer *aspectContainer = objc_getAssociatedObject(self, aliasSelector);
        if (!aspectContainer) {
            aspectContainer = [AspectsContainer new];
            objc_setAssociatedObject(self, aliasSelector, aspectContainer, OBJC_ASSOCIATION_RETAIN);
        }
        return aspectContainer;
    }
    
    // 根据selector的别名来获取容器,如果没有指定容器则返回nil。
    static AspectsContainer *aspect_getContainerForClass(Class klass, SEL selector) {
        NSCParameterAssert(klass);
        AspectsContainer *classContainer = nil;
        do {
            classContainer = objc_getAssociatedObject(klass, selector);
            if (classContainer.hasAspects) break;
        }while ((klass = class_getSuperclass(klass)));
    
        return classContainer;
    }
    
    // 设置别名selector的容器为nil。
    static void aspect_destroyContainerForObject(id<NSObject> self, SEL selector) {
        NSCParameterAssert(self);
        SEL aliasSelector = aspect_aliasForSelector(selector);
        objc_setAssociatedObject(self, aliasSelector, nil, OBJC_ASSOCIATION_RETAIN);
    }
    
    ///////////////////////////////////////////////////////////////////////////////////////////
    #pragma mark - Selector Blacklist Checking
    
    // 黑魔法的集合,仅仅在进程中保持一份。key为class,value为AspectTracker
    static NSMutableDictionary *aspect_getSwizzledClassesDict() {
        static NSMutableDictionary *swizzledClassesDict;
        static dispatch_once_t pred;
        dispatch_once(&pred, ^{
            swizzledClassesDict = [NSMutableDictionary new];
        });
        return swizzledClassesDict;
    }
    
    // 判断selector方法是可以被钩子并添加痕迹
    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.
        NSString *selectorName = NSStringFromSelector(selector);
        if ([disallowedSelectorList containsObject:selectorName]) {
            NSString *errorDescription = [NSString stringWithFormat:@"Selector %@ is blacklisted.", selectorName];
            AspectError(AspectErrorSelectorBlacklisted, errorDescription);
            return NO;
        }
    
        // 如果selector是dealloc并且position不是before,那么就报错。
        // Additional checks.
        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;
        }
    
        // 如果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;
        }
    
        // 查找当前类和类的层次,是否已经修改了。如果已经修改并没有parent,则返回YES,不然返回NO。也就是说在类的层级中,只要一个class添加了hook,那么在子类或父类中就不能再添加方法的hook。
        // 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];
            do {
                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)));
    
            // 记录需要钩子的类,创建tracker对象保存到黑魔法的集合中。 并会遍历整个类层级,在每一个类中添加tracker。
            // 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;
    }
    
    // 从容器中删除切面痕迹类,一直遍历所有父类并逐一删除。
    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];
        do {
            AspectTracker *tracker = swizzledClassesDict[currentClass];
            if (tracker) {
                [tracker.selectorNames removeObject:selectorName];
                if (tracker.selectorNames.count == 0) {
                    [swizzledClassesDict removeObjectForKey:tracker];
                }
            }
        }while ((currentClass = class_getSuperclass(currentClass)));
    }
    
    @end
    
    @implementation AspectTracker
    
    // 初始化跟踪
    - (id)initWithTrackedClass:(Class)trackedClass parent:(AspectTracker *)parent {
        if (self = [super init]) {
            _trackedClass = trackedClass;
            _parentEntry = parent;
            _selectorNames = [NSMutableSet new];
        }
        return self;
    }
    - (NSString *)description {
        return [NSString stringWithFormat:@"<%@: %@, trackedClass: %@, selectorNames:%@, parent:%p>", self.class, self, NSStringFromClass(self.trackedClass), self.selectorNames, self.parentEntry];
    }
    
    @end
    
    ///////////////////////////////////////////////////////////////////////////////////////////
    #pragma mark - NSInvocation (Aspects)
    
    @implementation NSInvocation (Aspects)
    
    // NSInvocation的分类获取指定索引的参数
    // Thanks to the ReactiveCocoa team for providing a generic solution for this.
    - (id)aspect_argumentAtIndex:(NSUInteger)index {
        const char *argType = [self.methodSignature getArgumentTypeAtIndex:index];
        // Skip const type qualifier.
        if (argType[0] == _C_CONST) argType++;
    
    #define WRAP_AND_RETURN(type) do { type val = 0; [self getArgument:&val atIndex:(NSInteger)index]; return @(val); } while (0)
        if (strcmp(argType, @encode(id)) == 0 || strcmp(argType, @encode(Class)) == 0) {
            __autoreleasing id returnObj;
            [self getArgument:&returnObj atIndex:(NSInteger)index];
            return returnObj;
        } else if (strcmp(argType, @encode(SEL)) == 0) {
            SEL selector = 0;
            [self getArgument:&selector atIndex:(NSInteger)index];
            return NSStringFromSelector(selector);
        } else if (strcmp(argType, @encode(Class)) == 0) {
            __autoreleasing Class theClass = Nil;
            [self getArgument:&theClass atIndex:(NSInteger)index];
            return theClass;
            // Using this list will box the number with the appropriate constructor, instead of the generic NSValue.
        } else if (strcmp(argType, @encode(char)) == 0) {
            WRAP_AND_RETURN(char);
        } else if (strcmp(argType, @encode(int)) == 0) {
            WRAP_AND_RETURN(int);
        } else if (strcmp(argType, @encode(short)) == 0) {
            WRAP_AND_RETURN(short);
        } else if (strcmp(argType, @encode(long)) == 0) {
            WRAP_AND_RETURN(long);
        } else if (strcmp(argType, @encode(long long)) == 0) {
            WRAP_AND_RETURN(long long);
        } else if (strcmp(argType, @encode(unsigned char)) == 0) {
            WRAP_AND_RETURN(unsigned char);
        } else if (strcmp(argType, @encode(unsigned int)) == 0) {
            WRAP_AND_RETURN(unsigned int);
        } else if (strcmp(argType, @encode(unsigned short)) == 0) {
            WRAP_AND_RETURN(unsigned short);
        } else if (strcmp(argType, @encode(unsigned long)) == 0) {
            WRAP_AND_RETURN(unsigned long);
        } else if (strcmp(argType, @encode(unsigned long long)) == 0) {
            WRAP_AND_RETURN(unsigned long long);
        } else if (strcmp(argType, @encode(float)) == 0) {
            WRAP_AND_RETURN(float);
        } else if (strcmp(argType, @encode(double)) == 0) {
            WRAP_AND_RETURN(double);
        } else if (strcmp(argType, @encode(BOOL)) == 0) {
            WRAP_AND_RETURN(BOOL);
        } else if (strcmp(argType, @encode(bool)) == 0) {
            WRAP_AND_RETURN(BOOL);
        } else if (strcmp(argType, @encode(char *)) == 0) {
            WRAP_AND_RETURN(const char *);
        } else if (strcmp(argType, @encode(void (^)(void))) == 0) {
            __unsafe_unretained id block = nil;
            [self getArgument:&block atIndex:(NSInteger)index];
            return [block copy];
        } else {
            NSUInteger valueSize = 0;
            NSGetSizeAndAlignment(argType, &valueSize, NULL);
    
            unsigned char valueBytes[valueSize];
            [self getArgument:valueBytes atIndex:(NSInteger)index];
    
            return [NSValue valueWithBytes:valueBytes objCType:argType];
        }
        return nil;
    #undef WRAP_AND_RETURN
    }
    
    - (NSArray *)aspects_arguments {
        NSMutableArray *argumentsArray = [NSMutableArray array];
        for (NSUInteger idx = 2; idx < self.methodSignature.numberOfArguments; idx++) {
            [argumentsArray addObject:[self aspect_argumentAtIndex:idx] ?: NSNull.null];
        }
        return [argumentsArray copy];
    }
    
    @end
    
    ///////////////////////////////////////////////////////////////////////////////////////////
    #pragma mark - AspectIdentifier
    
    @implementation AspectIdentifier
    
    // 创建切面的识别
    + (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);
        if (!aspect_isCompatibleBlockSignature(blockSignature, object, selector, error)) {
            return nil;
        }
    
        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;
    }
    
    // 将原来想替换的block中参数设置到根据aspect_add传入block生成的block签名中,然后block签名执行aspect_add传入的block。
    - (BOOL)invokeWithInfo:(id<AspectInfo>)info {
        NSInvocation *blockInvocation = [NSInvocation invocationWithMethodSignature:self.blockSignature];
        NSInvocation *originalInvocation = info.originalInvocation;
        NSUInteger numberOfArguments = self.blockSignature.numberOfArguments;
    
        // Be extra paranoid. We already check that on hook registration.
        if (numberOfArguments > originalInvocation.methodSignature.numberOfArguments) {
            AspectLogError(@"Block has too many arguments. Not calling %@", info);
            return NO;
        }
    
        // The `self` of the block will be the AspectInfo. Optional.
        if (numberOfArguments > 1) {
            [blockInvocation setArgument:&info atIndex:1];
        }
        
        void *argBuf = NULL;
        for (NSUInteger idx = 2; idx < numberOfArguments; idx++) {
            const char *type = [originalInvocation.methodSignature getArgumentTypeAtIndex:idx];
            NSUInteger argSize;
            NSGetSizeAndAlignment(type, &argSize, NULL);
            
            if (!(argBuf = reallocf(argBuf, argSize))) {
                AspectLogError(@"Failed to allocate memory for block invocation.");
                return NO;
            }
            
            [originalInvocation getArgument:argBuf atIndex:idx];
            [blockInvocation setArgument:argBuf atIndex:idx];
        }
        
        [blockInvocation invokeWithTarget:self.block];
        
        if (argBuf != NULL) {
            free(argBuf);
        }
        return YES;
    }
    
    - (NSString *)description {
        return [NSString stringWithFormat:@"<%@: %p, SEL:%@ object:%@ options:%tu block:%@ (#%tu args)>", self.class, self, NSStringFromSelector(self.selector), self.object, self.options, self.block, self.blockSignature.numberOfArguments];
    }
    
    // 删除钩子的方法
    - (BOOL)remove {
        return aspect_remove(self, NULL);
    }
    
    @end
    
    ///////////////////////////////////////////////////////////////////////////////////////////
    #pragma mark - AspectsContainer
    
    @implementation AspectsContainer
    
    // 是否有切面识别
    - (BOOL)hasAspects {
        return self.beforeAspects.count > 0 || self.insteadAspects.count > 0 || self.afterAspects.count > 0;
    }
    
    // 根据options将切面识别 添加到对应的数组中
    - (void)addAspect:(AspectIdentifier *)aspect withOptions:(AspectOptions)options {
        NSParameterAssert(aspect);
        NSUInteger position = options&AspectPositionFilter;
        switch (position) {
            case AspectPositionBefore:  self.beforeAspects  = [(self.beforeAspects ?:@[]) arrayByAddingObject:aspect]; break;
            case AspectPositionInstead: self.insteadAspects = [(self.insteadAspects?:@[]) arrayByAddingObject:aspect]; break;
            case AspectPositionAfter:   self.afterAspects   = [(self.afterAspects  ?:@[]) arrayByAddingObject:aspect]; break;
        }
    }
    
    // 从容器中移除切面识别
    - (BOOL)removeAspect:(id)aspect {
        for (NSString *aspectArrayName in @[NSStringFromSelector(@selector(beforeAspects)),
                                            NSStringFromSelector(@selector(insteadAspects)),
                                            NSStringFromSelector(@selector(afterAspects))]) {
            NSArray *array = [self valueForKey:aspectArrayName];
            NSUInteger index = [array indexOfObjectIdenticalTo:aspect];
            if (array && index != NSNotFound) {
                NSMutableArray *newArray = [NSMutableArray arrayWithArray:array];
                [newArray removeObjectAtIndex:index];
                [self setValue:newArray forKey:aspectArrayName];
                return YES;
            }
        }
        return NO;
    }
    
    - (NSString *)description {
        return [NSString stringWithFormat:@"<%@: %p, before:%@, instead:%@, after:%@>", self.class, self, self.beforeAspects, self.insteadAspects, self.afterAspects];
    }
    
    @end
    
    ///////////////////////////////////////////////////////////////////////////////////////////
    #pragma mark - AspectInfo
    
    @implementation AspectInfo
    
    @synthesize arguments = _arguments;
    // 初始化切面信息
    - (id)initWithInstance:(__unsafe_unretained id)instance invocation:(NSInvocation *)invocation {
        NSCParameterAssert(instance);
        NSCParameterAssert(invocation);
        if (self = [super init]) {
            _instance = instance;
            _originalInvocation = invocation;
        }
        return self;
    }
    
    - (NSArray *)arguments {
        // Lazily evaluate arguments, boxing is expensive.
        if (!_arguments) {
            _arguments = self.originalInvocation.aspects_arguments;
        }
        return _arguments;
    }
    
    @end
    
    

    参考

    1. https://www.jianshu.com/p/1bc8205c0904

    相关文章

      网友评论

        本文标题:Runtime最佳实践之Aspects

        本文链接:https://www.haomeiwen.com/subject/eqeotltx.html