iOS 组件化常用方案的比较
组件化的几种方案:
方案一、url-block
通过在启动时注册组件提供的服务,把调用组件所使用的URL 和 组件提供的服务block对应起来,保存在内存中,在使用时候通过url找到对应的block从而获取服务;
示例:
注册:
. [MGJRouter registerURLPattern:@"mgj://detail?id=:id" toHandler:^(NSDictionary *routerParameters) {
. NSNumber *id = routerParameters[@"id"];
. // create view controller with id
. // push view controller
. }];
调用:
[MGJRouter openURL:@"mgj://detail?id=404"]
优点:
1,h5和app的原生交互,都可以直接使用这些定义好的路由;
2,统一iOS和Android的平台差异性,专门用后台来管理url,然后针对不同的平台,生成不同类型的文件,来方便使用;
缺点:
1,需要在内存中维护url-block的表,组件多了可能会有内存问题;
2,url的参数传递受到限制,只能传递常规的字符串参数,无法传递非常规参数,如UIImage、NSData等类型;
3,没有区分本地调用和远程调用的情况,尤其是远程调用,会因为url参数受限,导致一些功能受限;
4,组件本身依赖了中间件,且分散注册使的耦合较多;
5,url注册对于实施组件化是完全没有必要的,查找 URL 的实现不够高效;
6,路由写错后编译没问题,而实现运行就出问题了,不利于维护;
方案二、protocol-class
通过protocol 来定义服务接口,组件通过实现该接口来提供接口定义的服务,具体实现是通过protocol 和 class做一个映射,同时在内存中保存一张映射表,使用的时候通过protocol来找到对应的class获取相应的服务。
示例:
注册:
[ModuleManager registerClass:ClassA forProtocol:ProtocolA]
调用:
[ModuleManager classForProtocol:ProtocolA]
优点:
1,相对url-block方案来讲,解决了不能传递非常规参数的问题;
2,耦合代码量减少了,也利于日后的维护;
3,协议方法未实现的话,编译会报警告;
4,方法查找容易,调用比较高效;
缺点:
1,组件的方法调用比较分散;
2,内存中依然需要维护映射对应关系的表;
3,组件的协议需要注册,不注册就无法使用;
方案三、target-action
组件通过wrapper封装来给外界提供服务,调用者通过依然中间件来调用服务,而中间件是通过runtime来调用组件服务的,实现真正意义上的解耦,这是该方案最核心的地方,具体实现是给组件封装一个Target对象来对外提供服务,这样不会对原来组件造成入侵,然后调用者通过调用中间件category定义的接口来获取服务,这样调用者只需要依赖中间件而组件不需要依然中间件。
示例:
CTMediator分类
// CTMediator+CTMediatorModuleAActions.h
- (UIViewController *)CTMediator_viewControllerForDetail;
// CTMediator+CTMediatorModuleAActions.m
- (UIViewController *)CTMediator_viewControllerForDetail
{
return [self performTarget:@"TargetA" action:@"nativeFetchDetailViewController" params:@{@"key":@"value"} shouldCacheTarget:NO];
}
target
A组件
- (UIViewController *)Action_nativeFetchDetailViewController:(NSDictionary *)params;
这就要求target类名要加前缀Target_,方法名要加前缀Action_
调用者
// ViewController.h
#import "CTMediator+CTMediatorModuleAActions.h"
[self presentViewController:[[CTMediator sharedInstance] CTMediator_viewControllerForDetail] animated:YES completion:nil];
优点:
1,内存中不需要维护映射表;
2,不需要注册;
缺点:
1,中间件实现比较繁琐;
2,中间件方法、参数、返回值不够灵活;
3,中间件内部使用字符串来调用类和方法,如果字符串写错了,在编译期不会报错,但运行后会报错,不利于日后的维护;