前言
其实以前写过这么一片类似的文章链接,利用字符串
+runtime
能做到命名域级别的解耦,其实这种做法很极端,编码也很硬核,而且数据的类型也比较难确定,其实这也是Objc本身动态弱类型语言的缺点.
做了蛮久的iOS了,我就在前面的文章基础上分析几点自己的心得吧,如有不合适的地方,可以指正哈.demo地址
自己以前设计过得一个架构
结构图组件内
-
1.正常的业务模块,没什么好说的,可以写UI,业务逻辑,工具这样子的
-
2.AppDelegate在本模块中的一个接收类,负责去解耦主工程中杂糅的业务,例如分享组件可以把分享key注册等事件放到这个类中
-
3.ActionService分类,相当于组件对外暴露的一个接口,我们利用宏去规范它的命名,到时利用router去调用即可,这个架构的复杂点主要就在于如何去维护这么一个字符串常量列表,这里可以通过一些脚本扫描分类来减轻这个工作量.
UCACTION_SERVICE_EXTERN_METHOD(ModuleA, getVC, argu) { return [ModuleAVC new]; }
UCACTION_SERVICE_EXTERN_METHOD
这个宏主要是拼接组件名和方法名成为一个对象方法,起到规范命名的作用.
组件外
-
1.
router
,这里来负责派发方法可以这么调用UCROUTER_OPEN_NATIVE(ModuleA, getVC, nil)
,只要输入组件名,接口名即可,如果没参数的话不传就行. -
2.
AppDelegateExchange
这里负责交换我写的一个小工具UCAppDelegateReduce
和appDelegate
中的方法,然后遵从自身的生命周期到各个组件的AppDelegate
实现中去,支持位移枚举配置,支持Swift
.+ (void)load { UCAppDelegateMethodExchangeManager *manager = [UCAppDelegateMethodExchangeManager share]; // sendMessageType 是位移枚举,可以选择自己想给子模块派发的方法 UCAppDelegateConfigModel *model1 = [[UCAppDelegateConfigModel alloc] initWithModuleName:@"ModuleAAppDelegate" sendMessageType:didFinishLaunchingWithOptions]; UCAppDelegateConfigModel *model2 = [[UCAppDelegateConfigModel alloc] initWithModuleName:@"ModuleBAppDelegate" sendMessageType:handleOpenURL | didFinishLaunchingWithOptions]; [manager startExchangeMethodWithOriginalAppDelegateName:@"AppDelegate" newModuleAppDelegateConfigArray:@[model1, model2]]; }
-
3.
ActionService
其实是一个空类,每个组件会实现他的一个分类用作一个对外接口的作用.
近期在项目拆组件的一点心得
近期在拆主工程中的登录模块,我是想做成那种正确依赖,不依赖runtime这样的解耦方式,只要导入组件,他会把所有依赖的组件进行导入,实现一个完整的功能这么一个做法,比较理想,今天才把他做出来.
其实新项目,新模块你做组件还好,尽量少依赖外部,业务拆的清楚点基本还不算难做.拆老业务还是很头大的,有很多不属于登录模块的却还集成在登录这个文件里,我也是醉了,算是个吐槽吧.你导入一个,他要是依赖很多的话你还得想办法去解决,这就是个恶性循环了,在这点上看这个命名域解耦虽然偷懒了,但是拆老项目组件还是蛮好用的,我为了正确设计依赖把别的组件也改了不少,把不属于这个业务模块的全清掉了.现在也能做到导入登录的话能够导入相关依赖的模块了,是个完整功能可以运行了.
总结
个人还是偏向于正确的设计依赖,不要偷懒,所以我们在写项目的时候就要考虑好他的业务职责,尽量保持模块职责单一,依赖尽量保持纵向,如果横向依赖的话尽量还是用router
或者协议
去解决它.
另外不要为了组件化而去做组件化,可以把一些业务上或许能够复用的可以拆一下.
拆的话可以先从Service
层开始拆,比如分享,支付,map这些与业务牵扯比较小的,打下基石以后,拆业务也好拆一点.
最后这个AppDelegate
解耦的思路蛮不错的,他的动态派发经过了400多条的UT测试,还是比较稳的,也比较好扩展,这点可以用用看.
网友评论