利用runtime来给组件化项目appdelegate减负
前言
本文主要依赖我写的两个工具
1.UCRuntimeKit:这个小工具主要是为了能够利用字符串+runtime
动态的调用方法.经过了500多条单元测试,基本满足所有的使用场景,安全,且支持向调用方抛出error,但不会crash.在这里它主要是为了向各个组件中的delegate转发多参数方法用的.
2.UCAppDelegateReduce.这个小工具依赖上面的UCRuntimeKit
来做消息转发.
实现原理
-
1.先将项目中的delegate与框架中的
UCAppDelegateRealize
实现的22个方法进行交换,如果appdelegate没实现这个方法则不会交换,交换完成后不影响之前的逻辑,依旧会先调用原先appdelegate的逻辑,如果这22个方法没有包含你需要转发给组件的方法的话支持扩展. -
2.当delegate接收到调用时,会自动来到
UCAppDelegateRealize
,这里在会根据位移枚举的配置来对各个组件调用,这个调用过程依赖UCRuntimeKit
,十分安全,不会crash.
使用
可以利用cocoapod进行导入,pod 'UCAppDelegateReduce'
Objc中的使用
-
1.新建一个Objc类,例如我这里取名叫
AppDelegateExchange
-
2.在load类方法里进行下面的配置,就可以了
+ (void)load { UCAppDelegateMethodExchangeManager *manager = [UCAppDelegateMethodExchangeManager share]; // sendMessageType 是位移枚举,可以选择自己想给子模块派发的方法 UCAppDelegateConfigModel *model1 = [[UCAppDelegateConfigModel alloc] initWithModuleName:@"UCObjcModule1AppDelegate" sendMessageType:didFinishLaunchingWithOptions]; UCAppDelegateConfigModel *model2 = [[UCAppDelegateConfigModel alloc] initWithModuleName:@"UCObjcModule2AppDelegate" sendMessageType:handleOpenURL | didFinishLaunchingWithOptions]; [manager startExchangeMethodWithOriginalAppDelegateName:@"UCAppDelegate" newModuleAppDelegateConfigArray:@[model1, model2]]; }
Swift的使用
-
1.新建一个Objc类,例如我这里取名叫
AppDelegateExchange
-
2.要转发的Module中的appdelegate方法前要加
@objc
,否则不支持动态调用 -
3.在load类方法里进行下面的配置,就可以了
+ (void)load { UCAppDelegateMethodExchangeManager *manager = [UCAppDelegateMethodExchangeManager share]; // 这里Objc调用Swift需要加上类似命名空间的前缀,否则找不到这个Swift class NSString *swiftModule1Name = [UCMediatorParameterParser getObjcClassName:@"SwiftModule1AppDelegate"]; // 支持位移枚举 UCAppDelegateConfigModel *model1 = [[UCAppDelegateConfigModel alloc] initWithModuleName:swiftModule1Name sendMessageType:didFinishLaunchingWithOptions]; NSString *swiftModule2Name = [UCMediatorParameterParser getObjcClassName:@"SwiftModule2AppDelegate"]; UCAppDelegateConfigModel *model2 = [[UCAppDelegateConfigModel alloc] initWithModuleName:swiftModule2Name sendMessageType:handleOpenURL | didFinishLaunchingWithOptions]; NSString *originalDelegateName = [UCMediatorParameterParser getObjcClassName:@"AppDelegate"]; [manager startExchangeMethodWithOriginalAppDelegateName:originalDelegateName newModuleAppDelegateConfigArray:@[model1, model2]]; }
UCAppDelegateConfigModel
是很灵活的,支持位移枚举配置,配置后不会调用未配置的方法,另外manager的配置在app的生命周期中只应该在最开始load的时候配置一次!配置完成后这里会解析,生成类似这样的map,以代理方法名为key,需要转发的类名集合为value,并将这个map缓存在内存中,方便快速转发给各个组件.
这样你就可以把例如原先写在appdelegate中的开屏配置,分享key配置,支付配置,push路由配置,3Dtouch等等直接写在各自的模块中了,这里的调用顺序也是可以通过配置来决定的.
但是如果这个调用是异步的,例如组件B的一个功能依赖组件B的回调,建议还是把这个写在组件a的delegate实现里.
做完了这些你会发现你原来的delegate基本可以什么都不写了,他已经把业务分散到各个组件中去了.
UT
关于单元测试,这里基本只是测试了调用这个模块的,转发各个模块都是手动测得,判断参数能传入到各个组件就没有更深度的写了,这里的单元测试确实不太好写.