Method Swizzle的危機(jī)

在同時(shí)使用RAC和Aspects的時(shí)候,遇到了一個(gè)Crash,棧溢出了。

看了一下,是之前在項(xiàng)目中使用了RAC的rac_singalForSelector

@weakify(self);
[[viewController rac_signalForSelector:@selector(viewDidAppear:)] subscribeNext
:^(id x) {
      @strongify(self);
      self.shouldIgnorePushingViewControllers = NO;
}];

后來(lái)他又使用了Aspects庫(kù)中的aspect_hookSelector

    [UIViewController aspect_hookSelector:@selector(viewDidAppear:) withOptions
    :AspectPositionAfter usingBlock:^(id<AspectInfo> info, BOOL animated) {
        NSLog(@"AOP: %@ - %d", [info.instance class], animated);
    } error:NULL];

后來(lái)就仔細(xì)看了一下兩者的實(shí)現(xiàn),從接口上來(lái)說(shuō),RAC的rac_singalForSelector的實(shí)例對(duì)象方法Aspects的aspect_hookSelector類(lèi)對(duì)象方法。

第一感覺(jué)是前者針對(duì)是實(shí)例對(duì)象,后者針對(duì)的是類(lèi)對(duì)象。主要涉及的其實(shí)還是對(duì)象模型里的一些知識(shí),操作了類(lèi)對(duì)象和實(shí)例對(duì)象中的數(shù)據(jù)如果對(duì)對(duì)象模型不太熟悉,可以看一下我之前寫(xiě)的一篇Blog:對(duì)象模型

現(xiàn)在來(lái)分析下原因,從源碼入手,先來(lái)大致看RAC相關(guān)的源碼:

static RACSignal *NSObjectRACSignalForSelector(NSObject *self, SEL selector, 
                                               Protocol *protocol) {
  //aliasSelector是為了區(qū)分原Selector,RAC加了自己的前綴
    SEL aliasSelector = RACAliasForSelector(selector);

    @synchronized (self) {
         //這里是根據(jù)aliasSelector獲得相應(yīng)的熱信號(hào),這個(gè)熱信號(hào)主要是用于通知業(yè)務(wù)層的回調(diào)
         //也就是subscribeNext后面那一段block
        RACSubject *subject = objc_getAssociatedObject(self
                                                       , aliasSelector);
        if (subject != nil) return subject;

         //這個(gè)地方是基于當(dāng)前self類(lèi)創(chuàng)建了一個(gè)新類(lèi)型,有很多hook的邏輯都放在這個(gè)類(lèi)型中
         //具體邏輯在RACSwizzleClass函數(shù)中再分析
        Class class = RACSwizzleClass(self);
        NSCAssert(class != nil, @"Could not swizzle class of %@", self);

         //創(chuàng)建一個(gè)用于通知的熱信號(hào)
        subject = [[RACSubject subject] setNameWithFormat:@"%@ 
                   -rac_signalForSelector: %s", 
                   self.rac_description, 
                   sel_getName(selector)];

         //通過(guò)關(guān)聯(lián)對(duì)象的方式存儲(chǔ)熱信號(hào)
        objc_setAssociatedObject(self, 
                                 aliasSelector, 
                                 subject, 
                                 OBJC_ASSOCIATION_RETAIN);
        [self.rac_deallocDisposable addDisposable: 
                             [RACDisposable  disposableWithBlock:^{
                                  [subject sendCompleted];
        }]];

         //targetMethod是"viewDidApear"這個(gè)Selector的方法對(duì)象
        Method targetMethod = class_getInstanceMethod(class, selector);
        if (targetMethod == NULL) {
          //按照現(xiàn)有邏輯,這里應(yīng)該是走不到的,先不去看它
            const char *typeEncoding;
            if (protocol == NULL) {
            typeEncoding = RACSignatureForUndefinedSelector(selector);
            } else {
        // Look for the selector as an optional instance method.
                struct objc_method_description methodDescription =
                  protocol_getMethodDescription(protocol, selector, NO, YES);

                if (methodDescription.name == NULL) {
                // Then fall back to looking for a required 
                  //instance method.
                    methodDescription = 
                      protocol_getMethodDescription(protocol
                                                    , selector
                                                    , YES
                                                    , YES);
                    NSCAssert(methodDescription.name != NULL
                              , @"Selector %@ does not exist in <%s>"
                              ,NSStringFromSelector(selector)
                              , protocol_getName(protocol));
                }

                typeEncoding = methodDescription.types;
            }

            RACCheckTypeEncoding(typeEncoding);

            // Define the selector to call -forwardInvocation:.
            if (!class_addMethod(class, 
                                 selector,
                                 _objc_msgForward, 
                                 typeEncoding)) {
                NSDictionary *userInfo = @{
                    NSLocalizedDescriptionKey: 
                                         [NSString stringWithFormat:
                                                NSLocalizedString(
                                                  @"A race condition occurred 
                                                  implementing %@ on class %@"
                                                  , nil)
                                                ,NSStringFromSelector(selector)
                                                , class],
                    NSLocalizedRecoverySuggestionErrorKey: 
                   NSLocalizedString(@"Invoke -rac_signalForSelector: 
                                     again to override the implementation.", nil)
                };

                return [RACSignal error:[NSError errorWithDomain:
                                         RACSelectorSignalErrorDomain
                                code:RACSelectorSignalErrorMethodSwizzlingRace
                                         userInfo:userInfo]];
            }
          //_objc_msgForward是消息進(jìn)行轉(zhuǎn)發(fā)的開(kāi)始,這里主要是判斷原始的
          //方法對(duì)象有沒(méi)有被hook成_objc_msgForward,因?yàn)橄旅嬉_(kāi)始進(jìn)行方法實(shí)現(xiàn)的替換了
        } else if (method_getImplementation(targetMethod) != 
                   _objc_msgForward) {
            // Make a method alias for the existing 
             //method implementation.
            const char *typeEncoding =
              method_getTypeEncoding(targetMethod);
            RACCheckTypeEncoding(typeEncoding);
             //class_addMethod只是在當(dāng)前類(lèi)型對(duì)象(不會(huì)去基類(lèi)中查找)中
             //去找有沒(méi)有aliasSelector的方法,如果有就直接返回原來(lái)的方法實(shí)現(xiàn)
            //如果沒(méi)有就添加一個(gè)
            BOOL addedAlias __attribute__((unused)) = 
              class_addMethod(class, aliasSelector, 
                              method_getImplementation(targetMethod), 
                              typeEncoding);
            NSCAssert(addedAlias, @"Original implementation 
                      for %@ is already copied to %@ on %@", 
                      NSStringFromSelector(selector), 
                      NSStringFromSelector(aliasSelector), class);
            // Redefine the selector to call -forwardInvocation:.
             // 這里相當(dāng)于對(duì)原始方法進(jìn)行方法實(shí)現(xiàn)的替換,
             //只要調(diào)用原始方法,直接會(huì)開(kāi)始方法轉(zhuǎn)發(fā)的過(guò)程
            class_replaceMethod(class
                                , selector
                                , _objc_msgForward,
                                method_getTypeEncoding(targetMethod));
        }

        return subject;
    }
}

通過(guò)原始英文注釋加上后來(lái)的中文注釋?xiě)?yīng)該能比較好的理解大致的過(guò)程了

分為2部分

1是創(chuàng)建用于通知業(yè)務(wù)層回調(diào)的熱信號(hào)

2是Hook了當(dāng)前類(lèi),創(chuàng)建了新的子類(lèi)型,并將這個(gè)子類(lèi)型的原始selector進(jìn)行了方法實(shí)現(xiàn)的替換

既將原始selector實(shí)現(xiàn)替換成_objc_msgForward,增加了一個(gè)新的selector prefix_selector,

并將其實(shí)現(xiàn)為原始selector。另外個(gè)人覺(jué)得命名上最好是不要叫class了,可以改為subClass或者

swizzleClass,容易跟原始class搞混

接著就是RACSwizzleCalss函數(shù)了:

static Class RACSwizzleClass(NSObject *self) {
  //self.class和object_getClass返回的都是當(dāng)前實(shí)例的類(lèi)對(duì)象,好像沒(méi)什么區(qū)別???
    Class statedClass = self.class;
    Class baseClass = object_getClass(self);

    // The "known dynamic subclass" is the subclass generated by RAC.
    // It's stored as an associated object on every instance that's already
    // been swizzled, so that even if something else swizzles the class of
    // this instance, we can still access the RAC generated subclass.
    //這里官方說(shuō)明了子類(lèi)的用途,如果有其他地方swizzle了當(dāng)前類(lèi)對(duì)象,那也不太影響RAC自己的邏輯
    //因?yàn)樗械男畔⒍急4嬖谧约簞?chuàng)建的子類(lèi)中。
    Class knownDynamicSubclass = 
      objc_getAssociatedObject(self, RACSubclassAssociationKey);
    if (knownDynamicSubclass != Nil) return knownDynamicSubclass;

    NSString *className = NSStringFromClass(baseClass);

    if (statedClass != baseClass) {
         //這部分邏輯沒(méi)走到,先不看
        @synchronized (swizzledClasses()) {
            if (![swizzledClasses() containsObject:className]) {
                RACSwizzleForwardInvocation(baseClass);
                RACSwizzleRespondsToSelector(baseClass);
                RACSwizzleGetClass(baseClass, statedClass);
                RACSwizzleGetClass(object_getClass(baseClass), 
                                   statedClass);
                RACSwizzleMethodSignatureForSelector(baseClass);
                [swizzledClasses() addObject:className];
            }
        }

        return baseClass;
    }
     //加上RAC自己的前綴,給新的子類(lèi)命名
    const char *subclassName = [className stringByAppendingString:
                                RACSubclassSuffix].UTF8String;
    Class subclass = objc_getClass(subclassName);

    if (subclass == nil) {
        //createClass里面調(diào)用的是objc_allocateClassPair函數(shù)用于創(chuàng)建新的類(lèi)型對(duì)象,
        //它和下面的objc_registerClassPair函數(shù)是配對(duì)使用的
        subclass = [RACObjCRuntime createClass:subclassName 
                    inheritingFromClass:baseClass];
        if (subclass == nil) return nil;
         //這里是對(duì)新的子類(lèi)的forwardInvocation方法hook
        RACSwizzleForwardInvocation(subclass);
         //hookRespondsToSelector方法
        RACSwizzleRespondsToSelector(subclass);
         //hook了Class方法
        RACSwizzleGetClass(subclass, statedClass);
         //這里object_getClass得到的還是statedClass,既原始的類(lèi)。
        RACSwizzleGetClass(object_getClass(subclass), statedClass);
         //hook了方法簽名
        RACSwizzleMethodSignatureForSelector(subclass);
        //結(jié)束子類(lèi)的創(chuàng)建
        objc_registerClassPair(subclass);
    }
    //這里是將當(dāng)前實(shí)例對(duì)象的類(lèi)型信息改寫(xiě)成新的子類(lèi)
    object_setClass(self, subclass);
    //保存子類(lèi)信息
    objc_setAssociatedObject(self, RACSubclassAssociationKey, subclass, 
                             OBJC_ASSOCIATION_ASSIGN);
    return subclass;
}

RACSwizzleCalss函數(shù)里主要干的事情就是創(chuàng)建子類(lèi)型:

1.給新的子類(lèi)型命名

2.hook幾個(gè)重要的消息轉(zhuǎn)發(fā)方法,1是為了得到方法調(diào)用的入口 2是將子類(lèi)偽裝成原始的類(lèi)型

3.改變了實(shí)例對(duì)象的isa指針為新的子類(lèi),當(dāng)前實(shí)例對(duì)象的類(lèi)型信息為新的子類(lèi)信息

這里有必要看一下RACSwizzleGetClass函數(shù)的實(shí)現(xiàn):

static void RACSwizzleGetClass(Class class, Class statedClass) {
    SEL selector = @selector(class);
    Method method = class_getInstanceMethod(class, selector);
    IMP newIMP = imp_implementationWithBlock(^(id self) {
       //當(dāng)調(diào)用子類(lèi)的class方法的時(shí)候,返回的還是原始類(lèi)型對(duì)象
        return statedClass;
    });
    class_replaceMethod(class
    , selector
    , newIMP
    , method_getTypeEncoding(method));
}

這樣一來(lái),使用者感覺(jué)不到有什么異樣,不知道hook的存在了

最后重點(diǎn)看一下RACSwizzleForwardInvocation函數(shù):

static void RACSwizzleForwardInvocation(Class class) {
    SEL forwardInvocationSEL = @selector(forwardInvocation:);
    Method forwardInvocationMethod = 
      class_getInstanceMethod(class
                              , forwardInvocationSEL);

    // Preserve any existing implementation of -forwardInvocation:.
    void (*originalForwardInvocation)(id, SEL, NSInvocation *) = NULL;
    if (forwardInvocationMethod != NULL) {
        originalForwardInvocation =
(__typeof__(originalForwardInvocation))method_getImplementation(
          forwardInvocationMethod);
    }

    // Set up a new version of -forwardInvocation:.
    //
    // If the selector has been passed to -rac_signalForSelector:, invoke
    // the aliased method, and forward the arguments to any attached signals.
    //
    // If the selector has not been passed to -rac_signalForSelector:,
    // invoke any existing implementation of -forwardInvocation:. If there
    // was no existing implementation, throw an unrecognized selector
    // exception.
    id newForwardInvocation = ^(id self, NSInvocation *invocation) {
        BOOL matched = RACForwardInvocation(self, invocation);
        if (matched) return;

        if (originalForwardInvocation == NULL) {
            [self doesNotRecognizeSelector:invocation.selector];
        } else {
             //如果走到這里,基本上也要拋出異常了,一搬hook的都是必有的方法,已經(jīng)繞過(guò)了
             //原來(lái)的方法查找的過(guò)程到了消息轉(zhuǎn)發(fā)這一步
            originalForwardInvocation(self, forwardInvocationSEL, 
                                      invocation);
        }
    };

    class_replaceMethod(class, forwardInvocationSEL,
                        imp_implementationWithBlock(newForwardInvocation)
                        , "v@:@");
}

用newForwardInvocation替換了原來(lái)的forwardInvocation實(shí)現(xiàn),里面又調(diào)用了RACForwardInvocation函數(shù):

static BOOL RACForwardInvocation(id self, NSInvocation *invocation) {
    //這里的invocation還是原始的方法調(diào)用信息,手動(dòng)改成了帶前綴的selector
    SEL aliasSelector = RACAliasForSelector(invocation.selector);
    //獲取一下之前存儲(chǔ)的熱信號(hào)
    RACSubject *subject = objc_getAssociatedObject(self, aliasSelector);
    //這里的class得到的是RAC創(chuàng)建的子類(lèi),因?yàn)橹耙呀?jīng)改寫(xiě)了實(shí)例對(duì)象的ISA指針
    Class class = object_getClass(invocation.target);
    BOOL respondsToAlias = [class instancesRespondToSelector:aliasSelector];
    if (respondsToAlias) {
        //去改變selector為hook的新的selector,不然要死循環(huán)了
        invocation.selector = aliasSelector;
         //這一步就是真正原始的方法調(diào)用了,還記得之前已經(jīng)把a(bǔ)liasSelector的實(shí)現(xiàn)改為
         //原始Selector的實(shí)現(xiàn)了吧
        [invocation invoke];
    }

    if (subject == nil) return respondsToAlias;
    //通知業(yè)務(wù)層,要監(jiān)聽(tīng)的selector已經(jīng)被調(diào)用了,這個(gè)發(fā)生在原始方法調(diào)用之后
    [subject sendNext:invocation.rac_argumentsTuple];
    return YES;
}

前面幾個(gè)函數(shù)都是為這一步打基礎(chǔ)的,到了真正方法調(diào)用的時(shí)候,原始方法的調(diào)用以及通知業(yè)務(wù)層回調(diào)都在這里完成。

通過(guò)以上分析,現(xiàn)在通過(guò)一張圖總結(jié)一下:

RAC Swizzle Class

現(xiàn)在看一下Aspectsaspect_hookSelector的實(shí)現(xiàn),主要是aspect_prepareClassAndHookSelector函數(shù)

static void aspect_prepareClassAndHookSelector(NSObject *self, SEL selector
                                               , NSError **error) {
    NSCParameterAssert(selector);
   //這里等看aspect_hookClass具體分析其過(guò)程,暫時(shí)來(lái)看是生成了新子類(lèi)
    Class klass = aspect_hookClass(self, error);
   //獲得原始方法對(duì)象
    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]) {
          //添加alias方法,實(shí)現(xiàn)為原方法實(shí)現(xiàn)
            __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.
        //這里跟RAC一樣的做法,把原方法實(shí)現(xiàn)換成了_objc_msgForward
        //調(diào)原方法會(huì)直接開(kāi)始消息轉(zhuǎn)發(fā)的過(guò)程
        class_replaceMethod(klass
                            , selector
                            , aspect_getMsgForwardIMP(self, selector)
                            ,typeEncoding);
        AspectLog(@"Aspects: Installed hook for -[%@ %@].", klass,
                  NSStringFromSelector(selector));
    }
}

大致上來(lái)看,在方法實(shí)現(xiàn)的層面的處理和RAC很類(lèi)似.實(shí)際調(diào)試過(guò)程中,aspect_hookClass最終只是調(diào)用了aspect_swizzleClassInPlace,然后aspect_swizzleClassInPlace其實(shí)調(diào)用了aspect_swizzleForwardInvocation現(xiàn)在來(lái)看一下aspect_swizzleForwardInvocation函數(shù):

static void aspect_swizzleForwardInvocation(Class klass) {
    NSCParameterAssert(klass);
    // If there is no method, replace will act like class_addMethod.
    //將forwardInvocation方法實(shí)現(xiàn)替換成了__ASPECTS_ARE_BEING_CALLED__
    IMP originalImplementation = class_replaceMethod(klass
                                          ,@selector(forwardInvocation:)
                                          ,(IMP)__ASPECTS_ARE_BEING_CALLED__
                                           ,"v@:@");
    if (originalImplementation) {
     //alias的forwardInvocation換成了原始實(shí)現(xiàn)
        class_addMethod(klass, 
                        NSSelectorFromString(AspectsForwardInvocationSelectorName),
                        originalImplementation, "v@:@");
    }
    AspectLog(@"Aspects: %@ is now aspect aware.", NSStringFromClass(klass));
}

在消息轉(zhuǎn)發(fā)的最后關(guān)頭,調(diào)用ASPECTS_ARE_BEING_CALLED

static void __ASPECTS_ARE_BEING_CALLED__(__unsafe_unretained NSObject *self, 
                                         SEL selector, 
                                         NSInvocation *invocation) {
    NSCParameterAssert(self);
    NSCParameterAssert(invocation);
    SEL originalSelector = invocation.selector;
    //得到相應(yīng)的aliasSelector
    SEL aliasSelector = aspect_aliasForSelector(invocation.selector);
    //替換selector,因?yàn)閕nvocation中的selector還是原始的selector
    //不然遞歸死循環(huán)跟RAC一樣
    invocation.selector = aliasSelector;
    //通過(guò)aliasSelector得到hook的用戶回調(diào)
    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.
   //觸發(fā)那些在原始邏輯調(diào)用之前的回調(diào)
    aspect_invoke(classContainer.beforeAspects, info);
    aspect_invoke(objectContainer.beforeAspects, info);

    // Instead hooks.
    BOOL respondsToAlias = YES;
    if (objectContainer.insteadAspects.count || 
        classContainer.insteadAspects.count) {
          //直接是回調(diào)替換原始實(shí)現(xiàn)了
        aspect_invoke(classContainer.insteadAspects, info);
        aspect_invoke(objectContainer.insteadAspects, info);
    }else {
        Class klass = object_getClass(invocation.target);
        do {
            if ((respondsToAlias = [klass instancesRespondToSelector:
                                    aliasSelector])) {
                //這里是觸發(fā)原始方法的實(shí)現(xiàn)
                [invocation invoke];
                break;
            }
        }while (!respondsToAlias && (klass = class_getSuperclass(klass)));
    }

    // After hooks.
    //觸發(fā)那些在原始方法調(diào)用之后的用戶回調(diào)
    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)];
}

看樣子,在這種情況下A并沒(méi)有想RAC一樣創(chuàng)建新的子類(lèi)型,它是直接更改了原始類(lèi)型的方法信息。

用圖來(lái)表示一下它當(dāng)前的實(shí)現(xiàn):

Aspects Hook

和RAC比要簡(jiǎn)單一些,那么當(dāng)同時(shí)使用兩個(gè)庫(kù)Hook的時(shí)候會(huì)出現(xiàn)什么情況呢?按照文章開(kāi)頭的場(chǎng)景,RAC相當(dāng)于Hook了某個(gè)繼承自UIViewController的子類(lèi),并基于該子類(lèi)創(chuàng)建了新的子類(lèi)型Aspects相當(dāng)于直接Hook了UIViewController,對(duì)UIViewController本身的方法實(shí)現(xiàn)進(jìn)行了更改替換現(xiàn)在假設(shè)繼承自UIViewController業(yè)務(wù)子類(lèi)型叫做BusinessVieweController

還是用一張簡(jiǎn)略圖來(lái)表示兩個(gè)庫(kù)Hook之后的場(chǎng)景吧:

RAC和Aspects一起Hook

在類(lèi)的繼承結(jié)構(gòu)下,Hook之后的結(jié)果,Aspects在UIViewController這一層,RAC在subClass這一層當(dāng)有外界調(diào)用A方法時(shí),subClass會(huì)最終首先調(diào)用原始A方法的實(shí)現(xiàn)。如果說(shuō)在BusisnessViewController類(lèi)型中定義了A方法的實(shí)現(xiàn),并且在A方法中調(diào)用了super的A方法,類(lèi)似:

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    //業(yè)務(wù)代碼
    //.....
}

那這個(gè)時(shí)候會(huì)繼續(xù)調(diào)用到UIViewController這一層,這個(gè)時(shí)候就會(huì)開(kāi)始走UIViewController這一層的Hook流程了,還是一樣最終會(huì)調(diào)用到forwardInvocation這個(gè)方法,但是這個(gè)時(shí)候subClass已經(jīng)實(shí)現(xiàn)了這個(gè)方法,所以調(diào)用流程會(huì)回到子類(lèi)subClass的Hook流程中,見(jiàn)上圖中右上角的紅色虛線部分。后面的邏輯就是無(wú)限循環(huán),在兩個(gè)類(lèi)對(duì)象中往返直到棧溢出。

通過(guò)上面的分析,如果說(shuō)在BusinessViewController中沒(méi)有調(diào)用super的方法,那么不會(huì)引起死循環(huán)的,因?yàn)椴粫?huì)觸發(fā)UIViewController類(lèi)對(duì)象的Hook流程。并且當(dāng)觸發(fā)了死循環(huán)之后,會(huì)發(fā)現(xiàn)RAC訂閱的業(yè)務(wù)層的回調(diào)和BusinessViewController的A方法中除了Super那一句,剩下的業(yè)務(wù)代碼也沒(méi)有被執(zhí)行。另外,RAC這種Hook相對(duì)來(lái)說(shuō)會(huì)更安全一些(并不是說(shuō)Aspects就沒(méi)有Hook Class 的情況,只是當(dāng)前是這樣):它完全子類(lèi)化了業(yè)務(wù)類(lèi),并且將Hook全都保留在了新建的子類(lèi)型中,對(duì)其他類(lèi)型包括原始業(yè)務(wù)類(lèi)型沒(méi)有干擾并且這種Hook只針對(duì)了某個(gè)具體的實(shí)例對(duì)象,其他勢(shì)力對(duì)象如果沒(méi)有通過(guò)調(diào)用rac_singalForSelector并不會(huì)受到任何影響。

如果是直接Hook原始類(lèi)型,那么影響的面將是非常廣的,包括所有的實(shí)例對(duì)象和所有的子類(lèi)對(duì)象。

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

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

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