RAC中的RACSelectorSignal

其實(shí)這個(gè)源碼大部分的內(nèi)容都是runtime的,如果不了解runtime,這個(gè)看起來(lái)會(huì)比較蛋疼,源碼很多,分成一小部分一小部分慢慢看。
先看這個(gè)方法RACSwizzleForwardInvocation

//這個(gè)方法就是swizzle一個(gè)class的forwardInvocation函數(shù),熟悉oc方法消息轉(zhuǎn)發(fā)的同學(xué)都知道,當(dāng)一個(gè)對(duì)象收到一個(gè)不能響應(yīng)的消息,最后一步都會(huì)走到這個(gè)方法。
static void RACSwizzleForwardInvocation(Class class) {
    SEL forwardInvocationSEL = @selector(forwardInvocation:);
    Method forwardInvocationMethod = class_getInstanceMethod(class, forwardInvocationSEL);

    //如果forwardInvocation已經(jīng)有實(shí)現(xiàn)了,就存下。。
    void (*originalForwardInvocation)(id, SEL, NSInvocation *) = NULL;
    if (forwardInvocationMethod != NULL) {
        originalForwardInvocation = (__typeof__(originalForwardInvocation))method_getImplementation(forwardInvocationMethod);
    }
       //去定義新的forwardInvocation實(shí)現(xiàn)
    id newForwardInvocation = ^(id self, NSInvocation *invocation) {
               //如果已經(jīng)被rac_signalForSelector過(guò)了,直接走一遍RACForwardInvocation,然后返回
        BOOL matched = RACForwardInvocation(self, invocation);
        if (matched) return;
               //如果沒(méi)有的話就直接走遠(yuǎn)來(lái)的實(shí)現(xiàn)
        if (originalForwardInvocation == NULL) {
            [self doesNotRecognizeSelector:invocation.selector];
        } else {
            originalForwardInvocation(self, forwardInvocationSEL, invocation);
        }
    };

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

關(guān)于上段的RACForwardInvocation,源碼如下

static BOOL RACForwardInvocation(id self, NSInvocation *invocation) {
        //獲取帶rac_alias_前綴的方法
    SEL aliasSelector = RACAliasForSelector(invocation.selector);
       //可以看到sel其實(shí)也就是個(gè)const void *key
    RACSubject *subject = objc_getAssociatedObject(self, aliasSelector);

    Class class = object_getClass(invocation.target);
    BOOL respondsToAlias = [class instancesRespondToSelector:aliasSelector];
       //如果這個(gè)class有帶rac_alias_前綴的方法,就執(zhí)行
    if (respondsToAlias) {
        invocation.selector = aliasSelector;
        [invocation invoke];
    }

    if (subject == nil) return respondsToAlias;
        //給訂閱這發(fā)送invovation的入?yún)?    [subject sendNext:invocation.rac_argumentsTuple];
    return YES;
}

下面在繼續(xù)看RACSwizzleRespondsToSelector,其實(shí)這個(gè)方法就是去swizzle一個(gè)class的respondsToSelector的方法

static void RACSwizzleRespondsToSelector(Class class) {
    SEL respondsToSelectorSEL = @selector(respondsToSelector:);
    Method respondsToSelectorMethod = class_getInstanceMethod(class, respondsToSelectorSEL);
    BOOL (*originalRespondsToSelector)(id, SEL, SEL) = (__typeof__(originalRespondsToSelector))method_getImplementation(respondsToSelectorMethod);
       //和上面一個(gè)套路。。
    id newRespondsToSelector = ^ BOOL (id self, SEL selector) {
               //這個(gè)方法就是去根據(jù)selector去找一個(gè)class的method,其實(shí)系統(tǒng)有個(gè)方法
class_getInstanceMethod,不懂為啥要自己寫(xiě)。。
        Method method = rac_getImmediateInstanceMethod(class, selector);

        if (method != NULL && method_getImplementation(method) == _objc_msgForward) {
              //如果有alias的selector則返回yes,否則就返回原來(lái)的respondsToSelector的實(shí)現(xiàn)結(jié)果。
            SEL aliasSelector = RACAliasForSelector(selector);
            if (objc_getAssociatedObject(self, aliasSelector) != nil) return YES;
        }

        return originalRespondsToSelector(self, respondsToSelectorSEL, selector);
    };

    class_replaceMethod(class, respondsToSelectorSEL, imp_implementationWithBlock(newRespondsToSelector), method_getTypeEncoding(respondsToSelectorMethod));
}

下面繼續(xù)看RACSwizzleGetClass,這個(gè)就是去swizzle一個(gè)[self class] 這個(gè)get方法。

static void RACSwizzleGetClass(Class class, Class statedClass) {
    SEL selector = @selector(class);
    Method method = class_getInstanceMethod(class, selector);
    IMP newIMP = imp_implementationWithBlock(^(id self) {
                //返回statedClass
        return statedClass;
    });
    class_replaceMethod(class, selector, newIMP, method_getTypeEncoding(method));
}

熟悉runtime的都知道重寫(xiě)forwardInvocation,一定要重寫(xiě)方法簽名,也就是methodSignatureForSelector這個(gè)函數(shù)。下面就開(kāi)始看這個(gè)方法。

static void RACSwizzleMethodSignatureForSelector(Class class) {
    IMP newIMP = imp_implementationWithBlock(^(id self, SEL selector) {
                //這時(shí)候你去調(diào)self.class并不會(huì)拿到真實(shí)的,因?yàn)楸晃覀僺wizzle掉了
        Class actualClass = object_getClass(self);
        Method method = class_getInstanceMethod(actualClass, selector);
 //如果有這個(gè)方法,那直接返回簽名,如果沒(méi)有的話,那就調(diào)super
        if (method == NULL) {
            struct objc_super target = {
                .super_class = class_getSuperclass(class),
                .receiver = self,
            };
            NSMethodSignature * (*messageSend)(struct objc_super *, SEL, SEL) = (__typeof__(messageSend))objc_msgSendSuper;
//這個(gè)相當(dāng)于用[super ]
            return messageSend(&target, @selector(methodSignatureForSelector:), selector);
        }

        char const *encoding = method_getTypeEncoding(method);
        return [NSMethodSignature signatureWithObjCTypes:encoding];
    });

    SEL selector = @selector(methodSignatureForSelector:);
    Method methodSignatureForSelectorMethod = class_getInstanceMethod(class, selector);
    class_replaceMethod(class, selector, newIMP, method_getTypeEncoding(methodSignatureForSelectorMethod));
}

以上是基礎(chǔ)部分現(xiàn)在可以開(kāi)始看signalforselector這個(gè)方法了,其核心邏輯在下面這個(gè)方法中

static RACSignal *NSObjectRACSignalForSelector(NSObject *self, SEL selector, Protocol *protocol) {
        //獲取帶rac_alias_頭的方法,正常第一次都是沒(méi)有的
    SEL aliasSelector = RACAliasForSelector(selector);

    @synchronized (self) {
//如果已經(jīng)被rac_signalForSelector過(guò)了,那已經(jīng)有這個(gè)subject了,直接返回就行了
        RACSubject *subject = objc_getAssociatedObject(self, aliasSelector);
        if (subject != nil) return subject;
//這個(gè)方法上面已經(jīng)說(shuō)了,就是swizzzle這個(gè)class一些列協(xié)議轉(zhuǎn)發(fā)的方法。
        Class class = RACSwizzleClass(self);
        NSCAssert(class != nil, @"Could not swizzle class of %@", self);
//第一次去set下這個(gè)subject
        subject = [[RACSubject subject] setNameWithFormat:@"%@ -rac_signalForSelector: %s", self.rac_description, sel_getName(selector)];
        objc_setAssociatedObject(self, aliasSelector, subject, OBJC_ASSOCIATION_RETAIN);

        [self.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{
            [subject sendCompleted];
        }]];
//獲取這個(gè)方法
        Method targetMethod = class_getInstanceMethod(class, selector);
        if (targetMethod == NULL) {
//如果沒(méi)有的話,不會(huì)crash,會(huì)走下面的邏輯,首先去定義入?yún)⒌念?lèi)型,classaddmethod的時(shí)候會(huì)用到。
            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);

            // 去添加這個(gè)方法,如果不成功,能直接返回racsignal error
            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]];
            }
        } else if (method_getImplementation(targetMethod) != _objc_msgForward) {
//如果這個(gè)方法存在
            // Make a method alias for the existing method implementation.
            const char *typeEncoding = method_getTypeEncoding(targetMethod);

            RACCheckTypeEncoding(typeEncoding);
添加一個(gè)帶標(biāo)志為的方法。
            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);
//siwzzle這個(gè)selector的實(shí)現(xiàn),讓他繼續(xù)把消息發(fā)送出去這樣就能走到我們上面的forwardInvocation,那個(gè)地方我們做了自己的邏輯,_objc_msgForward就是發(fā)送消息。。
            // Redefine the selector to call -forwardInvocation:.
            class_replaceMethod(class, selector, _objc_msgForward, method_getTypeEncoding(targetMethod));
        }

        return subject;
    }
}
最后編輯于
?著作權(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ù)。

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

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 2,032評(píng)論 0 9
  • 文中的實(shí)驗(yàn)代碼我放在了這個(gè)項(xiàng)目中。 以下內(nèi)容是我通過(guò)整理[這篇博客] (http://yulingtianxia....
    茗涙閱讀 1,021評(píng)論 0 6
  • 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的...
    西木閱讀 30,874評(píng)論 33 466
  • 本文轉(zhuǎn)載自:http://yulingtianxia.com/blog/2014/11/05/objective-...
    ant_flex閱讀 867評(píng)論 0 1
  • 轉(zhuǎn)載:http://yulingtianxia.com/blog/2014/11/05/objective-c-r...
    F麥子閱讀 828評(píng)論 0 2

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