casa老師的方案主要是基於Mediator模式和Target-Action模式,中間採用了runtime來完成調用。swift
下面以Demo爲例,來分析一下組件化實施的方式。首先看一下Demo的項目結構:bash
CTMediator
類就是中間件類,負責遠程調用和本地組件間調用的處理和分發。函數
#import <UIKit/UIKit.h>
extern NSString * const kCTMediatorParamsKeySwiftTargetModuleName;
@interface CTMediator : NSObject
+ (instancetype)sharedInstance;
// 遠程App調用入口
- (id)performActionWithUrl:(NSURL *)url completion:(void(^)(NSDictionary *info))completion;
// 本地組件調用入口
- (id)performTarget:(NSString *)targetName action:(NSString *)actionName params:(NSDictionary *)params shouldCacheTarget:(BOOL)shouldCacheTarget;
- (void)releaseCachedTargetWithTargetName:(NSString *)targetName;
@end
複製代碼
其中遠程調用函數performActionWithUrl:completion:
是對url進行處理解析後轉化成本地調用。組件化
看一下本地調用函數的代碼實現:ui
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];
}
NSObject *target = self.cachedTarget[targetClassString];
if (target == nil) {
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;
}
if (shouldCacheTarget) {
self.cachedTarget[targetClassString] = target;
}
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];
[self.cachedTarget removeObjectForKey:targetClassString];
return nil;
}
}
複製代碼
首先獲取target實例。而後生成target要出發的消息SEL action,而後發送消息(調用函數)。url
DemoModule文件夾即表明一個具體的組件(模塊),下面簡稱AModule,Target-A
類即這個組件(模塊)對外暴露的可調用方法(對外接口)的具體實現,方法的實現都是基於組件內。那麼當別的地方想調用AModule時怎麼處理呢?並非直接引用Target-A
,若是這樣就與AModule耦合在了一塊兒,破壞了組件的獨立性。既然是Mediator模式,固然是有中間件,咱們看一下CTMediator+CTMediatorModuleAActions
這個類。這裏使用了分類來擴展CTMediator,增長了AModule的對外接口,保證了AModule的獨立性。若是之後出現了BModule,只須要建立一個CTMediator+CTMediatorModuleBActions
,來實現BModule的對外接口。spa
我的認爲casa的組件化方案整體是優於蘑菇街的組件化方案的。可是對蘑菇街URLProtocol
的方式加以改造,使用runtime的方式調用,就跟casa的方案接近同樣了,你們能夠試一下。至於openURL
的方式,若是隻支持本地調用,在Target-X
中註冊URL,是否是也相似Target-Action模式呢。3d
若是個人文章對你有所幫助,請留言告訴我,Thanks!code