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