iOS组件化解决方案
点击上方“iOS开发”,选择“置顶公众号”
关键时刻,第一时间送达!
先不说楚枫的这般年纪,能够踏入元武一重说明了什么,最主要的是,楚枫在刚刚踏入核心地带时,明明只是灵武七重,而在这两个月不到的时间,连跳两重修为,又跳过一个大境界,踏入了元武一重,这般进步速度,简直堪称变态啊。
“这楚枫不简单,原来是一位天才,若是让他继续成长下去,绝对能成为一号人物,不过可惜,他太狂妄了,竟与龚师兄定下生死约战,一年时间,他再厉害也无法战胜龚师兄。”有人认识到楚枫的潜力后,为楚枫感到惋惜。
“哼,何须一年,此子今日就必败,巫九与龚师兄关系甚好,早就看他不顺眼了,如今他竟敢登上生死台挑战巫九,巫九岂会放过他?”但也有人认为,楚枫今日就已是在劫难逃。
“何人挑战老子?”就在这时,又是一声爆喝响起,而后一道身影自人群之中掠出,最后稳稳的落在了比斗台上。
这位身材瘦弱,身高平平,长得那叫一个猥琐,金钩鼻子蛤蟆眼,嘴巴一张牙带色儿,说话臭气能传三十米,他若是当面对谁哈口气,都能让那人跪在地上狂呕不止。
不过别看这位长得不咋地,他在核心地带可是鼎鼎有名,剑道盟创建者,青龙榜第九名,正是巫九是也。
“你就是巫九?”楚枫眼前一亮,第一次发现,世间还有长得如此奇葩的人。
巫九鼻孔一张,大嘴一咧,拍着那干瘪的肚子,得意洋洋的道:“老子就是巫九,你挑战老子?”
“不是挑战你,是要宰了你。”楚枫冷声笑道。
“好,老子满足你这个心愿,长老,拿张生死状来,老子今日在这里了解了这小子。”巫九扯开嗓子,对着下方吼了一声。
如果他对内门长老这么说话,也就算了,但是敢这么跟核心长老说话的,他可真是算作胆肥的,就连许多核心弟子,都是倒吸了一口凉气,心想这楚枫够狂,想不到这巫九更狂。
不过最让人无言的就是,巫九话音落下不久,真有一位核心长老自人群走出,缓缓得来到了比斗台上,左手端着笔墨,右手拿着生死状,来到了巫九的身前。
“我去,这巫九什么身份,竟能这般使唤核心长老?”有人吃惊不已,那长老修为不低,乃是元武七重,比巫九还要高两个层次,但却这般听巫九的话,着实让人吃惊不已。
“这你就不知道了吧,巫九在前些时日,拜了钟离长老为师尊,已正式得到钟离长老的亲传。”有人解释道。
“钟离长老?可是那位性情古怪的钟离一护?”
“没错,就是他。”
“天哪,巫九竟然拜入了他的门下?”
人们再次大吃一惊,那钟离一护在青龙宗可是赫赫有名,若要是论其个人实力,在青龙宗内绝对能够排入前三,连护宗六老单打独斗都不会是他的对手。
只不过那钟离一护,如同诸葛青云一样,也是一位客卿长老,所以在青龙宗内只是挂个头衔,什么事都不管,更别说传授宗内弟子技艺了,如今巫九竟然能拜入他老人家门下,着实让人羡慕不已。
“恩怨生死台,的确可以决斗生死,但必须要有所恩怨,你们两个人,可有恩怨?”那位长老开口询问道。
先不说楚枫的这般年纪,能够踏入元武一重说明了什么,最主要的是,楚枫在刚刚踏入核心地带时,明明只是灵武七重,而在这两个月不到的时间,连跳两重修为,又跳过一个大境界,踏入了元武一重,这般进步速度,简直堪称变态啊。
“这楚枫不简单,原来是一位天才,若是让他继续成长下去,绝对能成为一号人物,不过可惜,他太狂妄了,竟与龚师兄定下生死约战,一年时间,他再厉害也无法战胜龚师兄。”有人认识到楚枫的潜力后,为楚枫感到惋惜。
“哼,何须一年,此子今日就必败,巫九与龚师兄关系甚好,早就看他不顺眼了,如今他竟敢登上生死台挑战巫九,巫九岂会放过他?”但也有人认为,楚枫今日就已是在劫难逃。
“何人挑战老子?”就在这时,又是一声爆喝响起,而后一道身影自人群之中掠出,最后稳稳的落在了比斗台上。
这位身材瘦弱,身高平平,长得那叫一个猥琐,金钩鼻子蛤蟆眼,嘴巴一张牙带色儿,说话臭气能传三十米,他若是当面对谁哈口气,都能让那人跪在地上狂呕不止。
不过别看这位长得不咋地,他在核心地带可是鼎鼎有名,剑道盟创建者,青龙榜第九名,正是巫九是也。
“你就是巫九?”楚枫眼前一亮,第一次发现,世间还有长得如此奇葩的人。
巫九鼻孔一张,大嘴一咧,拍着那干瘪的肚子,得意洋洋的道:“老子就是巫九,你挑战老子?”
“不是挑战你,是要宰了你。”楚枫冷声笑道。
“好,老子满足你这个心愿,长老,拿张生死状来,老子今日在这里了解了这小子。”巫九扯开嗓子,对着下方吼了一声。
如果他对内门长老这么说话,也就算了,但是敢这么跟核心长老说话的,他可真是算作胆肥的,就连许多核心弟子,都是倒吸了一口凉气,心想这楚枫够狂,想不到这巫九更狂。
不过最让人无言的就是,巫九话音落下不久,真有一位核心长老自人群走出,缓缓得来到了比斗台上,左手端着笔墨,右手拿着生死状,来到了巫九的身前。
“我去,这巫九什么身份,竟能这般使唤核心长老?”有人吃惊不已,那长老修为不低,乃是元武七重,比巫九还要高两个层次,但却这般听巫九的话,着实让人吃惊不已。
“这你就不知道了吧,巫九在前些时日,拜了钟离长老为师尊,已正式得到钟离长老的亲传。”有人解释道。
“钟离长老?可是那位性情古怪的钟离一护?”
“没错,就是他。”
“天哪,巫九竟然拜入了他的门下?”
人们再次大吃一惊,那钟离一护在青龙宗可是赫赫有名,若要是论其个人实力,在青龙宗内绝对能够排入前三,连护宗六老单打独斗都不会是他的对手。
只不过那钟离一护,如同诸葛青云一样,也是一位客卿长老,所以在青龙宗内只是挂个头衔,什么事都不管,更别说传授宗内弟子技艺了,如今巫九竟然能拜入他老人家门下,着实让人羡慕不已。
“恩怨生死台,的确可以决斗生死,但必须要有所恩怨,你们两个人,可有恩怨?”那位长老开口询问道。
由于近期迭代周期变长,有时间想想代码持续改进的问题,再加上各业务模块代码从去年杂乱无章的状态,到目前整体结构基本清晰,进而想到了模块之间解耦的问题,于是有了本文,关于iOS组件化的一些思路及最终的解决方案。
为什么要组件化
技术界如今已存在很多关于组件化的解决方案,Class-Protocol、Target-Action等等,无论采用哪种方案,大家的目的都是为了解决代码庞大到一定规模时,依旧可以比较方便的进行管理和开发。这个时候就需要对各个业务模块进行梳理,在代码层面实现高内聚、低耦合,降低它们相互之间的变化带来的影响,从而提升开发效率。
先来看看如下两个图,对比一下:
模块间跳转现状.jpg
中间层框架解耦方案.jpg
从图中可以看出,在经过中间层框架跳转分发之后,各业务模块之间不存在引用关系,代码相互隔离,调用层次清晰,实现了模块间的真正解耦,完美的过渡到组件化的流程。
框架内部的实现原理是什么
这里采用的是openURL: 和 openWithMapKey:的两种调用方式,以便实现App之间跳转及模块之间的跳转操作,具体采用哪种方式之后会讲到,下面来看一下中间层框架 JCNavigator 简单的调用过程:
中间层跳转分发流程.jpg
接下来详细介绍下流程中出现的方法及相关类:
openURL:
支持App之间的跳转
支持设置、电话等系统Apps和info.plist白名单中的第三方Apps跳转
支持Module之间的跳转
传参时仅支持NSString数据类型的赋值
支持Module内部页面的跳转
传参时仅支持NSString数据类型的赋值
openWithMapKey:
支持Module内部页面的跳转
传参时支持NSString、NSArray、UIImage等系统数据类型及自定义数据类型的赋值
支持Module之间的跳转
为了模块间的解耦,传参时建议使用系统数据类型,避免使用自定义数据类型
总结:两种调用方法各有优势,通过推送、Widget、第三方App等外部入口打开你的App执行跳转操作时,建议使用openURL:,其他情况的跳转都采用openWithMapKey:的调用方式。
JCModuleMap
从上图可以看出,模块间无论是通过 openURL: 还是 openWithMapKey: 方法,都是找到对应的JCModuleMap,然后实现最终的页面跳转。接下来看看如何通过JCModuleMap实现这一操作:
子类化
JCModuleMap子类化.jpg
// JCTestModuleMap.m
NSString *const JCFirstLevelMapKey = @"JC_firstLevel";
NSString *const JCSecondLevelMapKey = @"JC_secondLevel";
NSString *const JCThirdLevelMapKey = @"JC_thirdLevel";
NSString *const JCContentDetailMapKey = @"JC_contentDetail";
@implementation JCTestModuleMap
- (NSString *)mapKeyPrefix
{
return @"JC";
}
- (NSDictionary< NSString *,Class> *)classesForMapKeys
{
return @{JCFirstLevelMapKey: NSClassFromString(@"JCFirstLevelViewController"),
JCSecondLevelMapKey: NSClassFromString(@"JCSecondLevelViewController"),
JCThirdLevelMapKey: NSClassFromString(@"JCThirdLevelViewController"),
JCContentDetailMapKey: NSClassFromString(@"JCContentDetailViewController"),
};
}
@end
NSURL/mapKey映射原理
NSURL:mapKey映射原理.jpg
总结:openURL: 通过NSURL及子类化JCModuleMap中实现的mapKeyPrefix拼接对应的mapKey,然后和 openWithMapKey: 一样,都是通过classesForMapKeys方法,获取class-mapKey的映射关系,进而跳转到module中对应class的视图控制器页面。
参数传递
申明接口协议,以属性的方式传递:
@protocol JC_contentDetail < NSObject>
@property (nonatomic, strong) NSString *currentIndex;
@property (nonatomic, strong) NSString *testId;
@property (nonatomic, strong) NSArray *testArray;
@end
@interface JCContentDetailViewController : UIViewController< JC_contentDetail>
@end
通过属性名-属性值生成字典传参:
+ (void)openContentDetailViewControllerWithCurrentIndex:(NSString *)currentIndex testId:(NSString *)testId testArray:(NSArray *)testArray
{
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:3];
if ([currentIndex isKindOfClass:[NSString class]]) {
params[@"currentIndex"] = currentIndex;
}
if ([testId isKindOfClass:[NSString class]]) {
params[@"testId"] = testId;
}
if ([testArray isKindOfClass:[NSArray class]]) {
params[@"testArray"] = testArray;
}
[[JCNavigator sharedNavigator] openWithMapKey:JCContentDetailMapKey propertiesBlock:^NSDictionary *{
return params;
} presented:YES animated:YES];
}
页面展示效果设置
openURL: 时,通过JCModuleMap子类化实现的方法设置:
// 是否模态弹出(默认NO)
- (BOOL)presentedForClass:(Class)viewControllerClass;
// 是否有动画(默认YES)
- (BOOL)animatedForClass:(Class)viewControllerClass;
openWithMapKey:方法调用时直接设置:
// 是否模态及动画
- (void)openWithMapKey:(NSString *)mapKey propertiesBlock:(JCNavigatorPropertiesBlock)block presented:(BOOL)presented animated:(BOOL)animated;
Modules之间的解耦是怎么实现的
好了,在实现JCModuleMap子类化及相关跳转配置之后,现在最关键的操作来了,如何为各个modules之间提供通信及调用的接口,才能最大限度的解决解耦的问题?废话不多说,先来看看这段代码:
// JCNavigator+JCTestModuleInterface.h
@interface JCNavigator (JCTestModuleInterface)
+ (void)openFirstLevelViewController;
+ (void)openSecondLevelViewController;
@end
// JCNavigator+JCTestModuleInterface.m
@implementation JCNavigator (JCTestModuleInterface)
+ (void)load
{
[[JCNavigator sharedNavigator] addModuleMap:[JCTestModuleMap new]];
}
+ (void)openFirstLevelViewController
{
[[JCNavigator sharedNavigator] openWithMapKey:JCFirstLevelMapKey];
}
+ (void)openSecondLevelViewController
{
[[JCNavigator sharedNavigator] openWithMapKey:JCSecondLevelMapKey];
}
@end
从代码可以看出:
1)每个module声明并实现对应的JCNavigator类别;
2)在JCNavigator类别中实现load类方法,添加对应子类化JCModuleMap对象;
3)JCNavigator类别头文件中提供统一的对外接口,实现文件中封装内部调用细节,从而解决modules之间的耦合问题。
下图概述了实现过程:
Modules接口服务.jpg
总结
对于组件化的介绍,到这里接近尾声,整个解决方案有优点也有缺点,需要开发者各自权衡:
优点
1)支持Apps之间跳转;
2)支持Modules之间跳转及通信(参数传递);
3)所有跳转只基于JCNavigator中间层框架;
4)可实现Modules之间解耦、互不依赖;
5)无需额外处理Modules页面间的层级关系。
缺点
1)需要子类化JCModuleMap,并将实例化对象添加到JCNavigator,增加了内存消耗;
2)如果viewController类名或传递的参数发生改变,Xcode不会报错也没有警告,需及时维护子类化JCModuleMap的实现,并更新JCNavigator类别中的调用代码。
关于框架的更多实现细节,请关注github开源代码
JCNavigator。https://github.com/imjoych/JCNavigator
https://mp.weixin.qq.com/s/z3tqvZkgu1EjI2Hj9AU8YQ
iOS开发整理发布,转载请联系作者获得授权
关注公众号:拾黑(shiheibook)了解更多
[广告]赞助链接:
四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/
随时掌握互联网精彩
- 1 习近平G20里约峰会展现大国担当 7981419
- 2 多国驻乌克兰大使馆因袭击风险关闭 7901931
- 3 78岁老太将减持2.5亿股股票 7822614
- 4 二十国集团里约峰会将会卓有成效 7747882
- 5 俄导弹击中乌水电站大坝 7627216
- 6 孙颖莎王艺迪不敌日本削球组合 7553981
- 7 高三女生酒后被强奸致死?检方回应 7462288
- 8 第一视角记录虎鲨吞下手机全程 7321127
- 9 手机不能看医院CT图像就要少收费 7214532
- 10 智慧乌镇点亮数字经济新未来 7191393