CTMediator 原理詳解(三)

前兩篇文章主要是對(duì)這篇文章的內(nèi)容進(jìn)行了一個(gè)鋪墊,這里就一起來(lái)看下 CTMediator 的實(shí)現(xiàn)原理

CTMediator 中最關(guān)鍵的一個(gè)方法:

- (id)performTarget:(NSString *)targetName action:(NSString *)actionNameparams:(NSDictionary *)params shouldCacheTarget:(BOOL)shouldCacheTarget;

看一下里面的具體實(shí)現(xiàn):

    // 從 params   字典中 獲取 swiftModuleName
    NSString *swiftModuleName = params[kCTMediatorParamsKeySwiftTargetModuleName];
    
    // generate target
    NSString *targetClassString = nil;
    if (swiftModuleName.length > 0) {
        targetClassString = [NSString stringWithFormat:@"%@.Target_%@", swiftModuleName, targetName];
    } else {
        targetClassString = [NSString stringWithFormat:@"Target_%@", targetName];
    }
    // 根據(jù) targetClassString 從 cachedTarget (緩存的Target)獲取 target 
    NSObject *target = self.cachedTarget[targetClassString];
    if (target == nil) {
        // 未獲取到 則生成一個(gè)target
        Class targetClass = NSClassFromString(targetClassString);
        target = [[targetClass alloc] init];
    }

    // generate action
    NSString *actionString = [NSString stringWithFormat:@"Action_%@:", actionName];
    SEL action = NSSelectorFromString(actionString);
    
    if (target == nil) {
        // 這里是處理無(wú)響應(yīng)請(qǐng)求的地方之一,這個(gè)demo做得比較簡(jiǎn)單,如果沒(méi)有可以響應(yīng)的target,就直接return了。實(shí)際開(kāi)發(fā)過(guò)程中是可以事先給一個(gè)固定的target專(zhuān)門(mén)用于在這個(gè)時(shí)候頂上,然后處理這種請(qǐng)求的
        [self NoTargetActionResponseWithTargetString:targetClassString selectorString:actionString originParams:params];
        return nil;
    }
    // 是否需要對(duì) Target 進(jìn)行緩存
    if (shouldCacheTarget) {
        // 將 Target 進(jìn)行緩存
        self.cachedTarget[targetClassString] = target;
    }

    // 判斷 Target 是否有 action 相應(yīng),避免crash
    if ([target respondsToSelector:action]) {
        // 這里是處理有響應(yīng)請(qǐng)求的地方
        return [self safePerformAction:action target:target params:params];
    } else {
        // 這里是處理無(wú)響應(yīng)請(qǐng)求的地方,如果無(wú)響應(yīng),則嘗試調(diào)用對(duì)應(yīng)target的notFound方法統(tǒng)一處理
        SEL action = NSSelectorFromString(@"notFound:");
        if ([target respondsToSelector:action]) {
            return [self safePerformAction:action target:target params:params];
        } else {
            // 這里也是處理無(wú)響應(yīng)請(qǐng)求的地方,在notFound都沒(méi)有的時(shí)候,這個(gè)demo是直接return了。實(shí)際開(kāi)發(fā)過(guò)程中,可以用前面提到的固定的target頂上的。
            [self NoTargetActionResponseWithTargetString:targetClassString selectorString:actionString originParams:params];
            // 刪除緩存的無(wú)用 Target
            [self.cachedTarget removeObjectForKey:targetClassString];
            return nil;
        }
    }

處理有響應(yīng)請(qǐng)求的地方會(huì)調(diào)用 - (id)safePerformAction:(SEL)action target:(NSObject *)target params:(NSDictionary *)params 方法

    // NSMethodSignature 該類(lèi)為對(duì)方法的參數(shù)、返回類(lèi)型進(jìn)行封裝
    NSMethodSignature* methodSig = [target methodSignatureForSelector:action];
    if(methodSig == nil) {
        return nil;
    }
    // 獲取返回類(lèi)型
    const char* retType = [methodSig methodReturnType];
    // 判斷返回值 類(lèi)型 
    if (strcmp(retType, @encode(void)) == 0) {
        // 用來(lái)包裝方法和對(duì)應(yīng)的對(duì)象,它可以存儲(chǔ)方法的名稱(chēng),對(duì)應(yīng)的對(duì)象,對(duì)應(yīng)的參數(shù)
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
        [invocation setArgument:&params atIndex:2];
        [invocation setSelector:action];
        [invocation setTarget:target];
        // 執(zhí)行NSInvocation對(duì)象中指定對(duì)象的指定方法,并且傳遞指定的參數(shù)
        [invocation invoke];
        return nil;
    }

    if (strcmp(retType, @encode(NSInteger)) == 0) {
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
        [invocation setArgument:&params atIndex:2];
        [invocation setSelector:action];
        [invocation setTarget:target];
        [invocation invoke];
        NSInteger result = 0;
        // 將返回?cái)?shù)據(jù)拷貝到提供的緩存區(qū)(retLoc)內(nèi)
        [invocation getReturnValue:&result];
        return @(result);
    }

    if (strcmp(retType, @encode(BOOL)) == 0) {
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
        [invocation setArgument:&params atIndex:2];
        [invocation setSelector:action];
        [invocation setTarget:target];
        [invocation invoke];
        BOOL result = 0;
        [invocation getReturnValue:&result];
        return @(result);
    }

    if (strcmp(retType, @encode(CGFloat)) == 0) {
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
        [invocation setArgument:&params atIndex:2];
        [invocation setSelector:action];
        [invocation setTarget:target];
        [invocation invoke];
        CGFloat result = 0;
        [invocation getReturnValue:&result];
        return @(result);
    }

    if (strcmp(retType, @encode(NSUInteger)) == 0) {
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
        [invocation setArgument:&params atIndex:2];
        [invocation setSelector:action];
        [invocation setTarget:target];
        [invocation invoke];
        NSUInteger result = 0;
        [invocation getReturnValue:&result];
        return @(result);
    }
    // 利用RunTime 向target對(duì)象傳遞消息,執(zhí)行 target 中 action 的方法,傳遞參數(shù) params
    return [target performSelector:action withObject:params];

總結(jié):
CTMediator 的實(shí)現(xiàn)得益于RunTime的存在,正因?yàn)槿绱宋覀兛梢越怦罡鱾€(gè)模塊,實(shí)現(xiàn)App之間的模塊化,這應(yīng)該也是很多iOS開(kāi)發(fā)不愿意完全舍棄OC的原因吧。

?著作權(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)容僅代表作者本人觀(guān)點(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,068評(píng)論 0 9
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒(méi)有地址/指針的概念1.2> 泛型1.3> 類(lèi)型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,666評(píng)論 1 32
  • http://casatwy.com/modulization_in_action.html 前述 國(guó)內(nèi)業(yè)界大家對(duì)...
    yuditxj閱讀 1,237評(píng)論 2 6
  • 在上一篇中對(duì)基礎(chǔ)組件進(jìn)行了拆分,接下來(lái)會(huì)拆分業(yè)務(wù)組件。業(yè)務(wù)組件最簡(jiǎn)單的理解(比如,有3個(gè)tabbar專(zhuān)題、...
    我阿鄭閱讀 15,736評(píng)論 15 38
  • 煙雨江南一直是優(yōu)美的所在,是解不開(kāi)的情懷。一團(tuán)云,一片雨,迎面半山風(fēng)雨,回程半山水墨,都是江南的風(fēng)韻。 ...
    慕涵塵閱讀 404評(píng)論 0 0

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