人生"码农"无闲暇,忙里偷闲得几回。最近在思考项目项目组件化的问题,重翻了前段时间iOS圈关于组件化的讨论,这里做下梳理和自己的总结。
说到组件化的技术方案,最早是Limboy分享了一篇蘑菇街组件化的技术方案,接着Casa提出了不同意见,后来Limboy在Casa反馈之上对自己方案做了进一步优化,最后Bang在前三篇文章基础之上做了清晰的梳理总结。通读之后,获益颇多,现总结如下:
![1672235-97278b0840782d7b.png](https://i-blog.csdnimg.cn/blog_migrate/55f4eaf69494be7278e9aa3e79f5d156.png)
一、MGJRouter的简单使用
蘑菇街团队提供了MGJRouter路由库,使用比较简单,其原理主要是通过注册URL来实现路由跳转。主要有两个步骤:① 注册URL生成路由表
② openUrl实现跳转
应用场景:
1.vc之间的跳转(传值/反向传值)
核心代码如下:
(1).注册URL
NS_ASSUME_NONNULL_BEGIN
@interface RouterManager : NSObject
@end
NS_ASSUME_NONNULL_END
#import "RouterManager.h"
#import <MGJRouter.h>
#import "TestOneViewController.h"
#import "TestTwoViewController.h"
@implementation RouterManager
+(void)load {
[MGJRouter registerURLPattern:@"mgj://loadFirstViewController" toHandler:^(NSDictionary *routerParameters) {
BaseNavigationController *navigationVC = routerParameters[MGJRouterParameterUserInfo][@"navigationVC"];
FirstViewController *vc = [[FirstViewController alloc] init];
[navigationVC pushViewController:vc animated:YES];
}];
[MGJRouter registerURLPattern:@"mgj://loadSecondViewController" toHandler:^(NSDictionary *routerParameters) {
UINavigationController *navigationVC = routerParameters[MGJRouterParameterUserInfo][@"navigationVC"];
NSString *labelText = routerParameters[MGJRouterParameterUserInfo][@"text"];
SecondViewController *vc = [[SecondViewController alloc] init];
vc.labelText = labelText;
[navigationVC pushViewController:vc animated:YES];
}];
[MGJRouter registerURLPattern:@"mgj://loadThirdViewController" toHandler:^(NSDictionary *routerParameters) {
UINavigationController *navigationVC = routerParameters[MGJRouterParameterUserInfo][@"navigationVC"];
void(^block)(NSString *) = routerParameters[MGJRouterParameterUserInfo][@"block"];
ThirdViewController *vc = [[ThirdViewController alloc] init];
vc.clicked = block;
[navigationVC pushViewController:vc animated:YES];
}];
[MGJRouter registerURLPattern:@"mgj://loadFourthViewController" toObjectHandler:^id(NSDictionary *routerParameters) {
NSString *labelText = routerParameters[MGJRouterParameterUserInfo][@"text"];
FourthViewController *vc = [[FourthViewController alloc] init];
vc.labelText = labelText;
return vc;
}];
}
@end
(2).调用url
- (IBAction)firstClick:(UIButton *)sender {
[MGJRouter openURL:@"mgj://loadFirstViewController"
withUserInfo:@{@"navigationVC" : self.navigationController}
completion:nil];
}
- (IBAction)secondClick:(UIButton *)sender {
[MGJRouter openURL:@"mgj://loadSecondViewController"
withUserInfo:@{@"navigationVC" : self.navigationController,
@"text": @"我喜欢出发"
}
completion:nil];
}
- (IBAction)thirdClick:(UIButton *)sender {
[MGJRouter openURL:@"mgj://loadThirdViewController"
withUserInfo:@{@"navigationVC" : self.navigationController,
@"block":^(NSString * text){
NSLog(@"%@",text);
},
}
completion:nil];
}
- (IBAction)fourClick:(UIButton *)sender {
NSString *textStr = @"模拟器32位处理器测试需要i386架构,模拟器64位处理器测试需要x86_64架构,真机32位处理器需要armv7,或者armv7s架构,真机64位处理器需要arm64架构";
[self.navigationController pushViewController:[MGJRouter objectForURL:@"mgj://loadFourthViewController" withUserInfo:@{@"text" : textStr}] animated:YES];
}
可打印看下routerParameters字典的内容:
{
MGJRouterParameterCompletion = "<__NSGlobalBlock__: 0x10cae0208>";
MGJRouterParameterURL = "mgj://loadTestOneViewController";
MGJRouterParameterUserInfo = {
navigationVC = "<BaseNavigationController: 0x7f9e6501f400>";
};
}
MGJRouter的简单使用就是这样,但是看这里不知道大家是否和我一样,有个疑惑,程序运行load方法会自动执行,为什么要在load方法里面写呢,接着往下看。。。
2. MGJRouter的弊端
① 每个业务组件,都需要一来这个MGJRouter框架
② URL维护成本高(url字符串写错,则不执行操作)
基于MGJRouter有以上弊端,这里引入Target-action方案,采用的是 CTMediator
这套方案.
![1672235-8d6c8f392f4c88a8.png](https://i-blog.csdnimg.cn/blog_migrate/1c784bae193f20c237347e9463bc7f11.png)
target-action方案原理:
- 每个组件, 提供一个统一披露的接口文件
- 额外的维护一个中间件的分类扩展(在此处进行硬解码 通过运行时进行物理解耦)
- 其他地方通过target-action;的方案进行交互
这里如何把模块做成私有pods就不过多介绍了,我这里就简单介绍下 CTMediator
库 但是用方法,没有按照标准的私有库结构去创建工程,具体可参考Target-Action方案主工程 Demo中的工程结构,这个是标准的组件库目录.
步骤:
(1).在项目中导入/pod 下CTMediator
库
(2).创建CTMediator+JumpTools
和Target_ClassController
类,具体代码见下图:
![1672235-e9d7c4299900eda2.png](https://i-blog.csdnimg.cn/blog_migrate/0ff743337f1234d48a282628176786c0.png)
我们再看下Target_ClassController
类里面的代码,如图:
![1672235-d4b8b2b5c6fbbf48.png](https://i-blog.csdnimg.cn/blog_migrate/4501cc79c88d93da3613c5dc62b6303c.png)
注意:
在
CTMediator+JumpTools
类中[self performTarget:<#(NSString *)#> action:<#(NSString *)#> params:<#(NSDictionary *)#> shouldCacheTarget:<#(BOOL)#>];
这个方法Target
和action
的字符串不是随便填写的,是按照一定的规则来的,而且Target_ClassController
类名字一定要以Target_XXXX
来开头,而且Target_XXXX
里面的方法,也一定要以-(void)Action_
为开头,具体原因是因为Casa大佬
的这个CTMediator
库,里面的performTarget
方法就是以Target_
和Action_
开头的,具体实现原理可以看CTMediator
库源码中的实现, 当然你也可以修改Casa大佬
的库的源码,也就一个类,但是如果你是pod到项目中的方式,不建议修改,就按照这种规则创建类名以及方法名即可。