CTMediator 原理解析(三)

前兩篇文章主要是對這篇文章的內容進行了一個鋪墊,這裏就一塊兒來看下 CTMediator 的實現原理 ,CTMediator是一個單例,主要是基於Mediator模式和Target-Action模式,中間採用了runtime來完成調用swift

CTMediator提供的API分別爲:遠程app調用入口本地組件調用入口釋放某個target緩存 這裏主要介紹 本地組件調用入口 也是咱們最經常使用的一個方法:緩存

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

實現分析:bash

// 從 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];
    }
    // 根據 targetClassString 從 cachedTarget (緩存的Target)獲取 target 
    NSObject *target = self.cachedTarget[targetClassString];
    if (target == nil) {
        // 未獲取到 則經過NSClassFromString將字符串轉爲應的類
        Class targetClass = NSClassFromString(targetClassString);
        target = [[targetClass alloc] init];
    }

    // generate action
    NSString *actionString = [NSString stringWithFormat:@"Action_%@:", actionName];
    SEL action = NSSelectorFromString(actionString);
    
    if (target == nil) {
        // 這裏是處理無響應請求的地方之一,這個demo作得比較簡單,若是沒有能夠響應的target,就直接return了。實際開發過程當中是能夠事先給一個固定的target專門用於在這個時候頂上,而後處理這種請求的
        [self NoTargetActionResponseWithTargetString:targetClassString selectorString:actionString originParams:params];
        return nil;
    }
    // 是否須要對 Target 進行緩存
    if (shouldCacheTarget) {
        // 將 Target 進行緩存
        self.cachedTarget[targetClassString] = target;
    }

    // 判斷target對象是否響應action,避免crash
    if ([target respondsToSelector:action]) {
        // 這裏是處理有響應請求的地方
        return [self safePerformAction:action target:target params:params];
    } else {
        // 這裏是處理無響應請求的地方,若是無響應,則嘗試調用對應target的notFound方法統一處理
        SEL action = NSSelectorFromString(@"notFound:");
        if ([target respondsToSelector:action]) {
            return [self safePerformAction:action target:target params:params];
        } else {
            // 這裏也是處理無響應請求的地方,在notFound都沒有的時候,這個demo是直接return了。實際開發過程當中,能夠用前面提到的固定的target頂上的。
            [self NoTargetActionResponseWithTargetString:targetClassString selectorString:actionString originParams:params];
            // 刪除緩存的無用 Target
            [self.cachedTarget removeObjectForKey:targetClassString];
            return nil;
        }
    }
複製代碼

處理有響應請求的地方會調用 - (id)safePerformAction:(SEL)action target:(NSObject *)target params:(NSDictionary *)params 方法app

// NSMethodSignature 記錄着某個方法的返回值類型信息以及參數類型信息。用於轉發消息接收者沒法響應的消息
    NSMethodSignature* methodSig = [target methodSignatureForSelector:action];
    if(methodSig == nil) {
        return nil;
    }
    // 獲取返回類型
    const char* retType = [methodSig methodReturnType];
    // 判斷返回值 類型 
    if (strcmp(retType, @encode(void)) == 0) {
        // 用來包裝方法和對應的對象,它能夠存儲方法的名稱,對應的對象,對應的參數
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
        [invocation setArgument:&params atIndex:2];
        [invocation setSelector:action];
        [invocation setTarget:target];
        // 執行NSInvocation對象中指定對象的指定方法,而且傳遞指定的參數
        [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;
        // 將返回數據拷貝到提供的緩存區(retLoc)內
        [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對象傳遞消息,執行 target 中 action 的方法,傳遞參數 params
    return [target performSelector:action withObject:params];
複製代碼

總結: CTMediator 根據得到的target和action信息,經過objective-C的runtime轉化生成target實例以及對應的action選擇器,而後最終調用到目標業務提供的邏輯,完成需求。ui

相關文章
相關標籤/搜索