前言
本文主要依賴我寫的兩個工具
1.UCRuntimeKit:這個小工具主要是為了能夠利用字符串+runtime動態(tài)的調(diào)用方法.經(jīng)過了500多條單元測試,基本滿足所有的使用場景,安全,且支持向調(diào)用方拋出error,但不會crash.在這里它主要是為了向各個組件中的delegate轉(zhuǎn)發(fā)多參數(shù)方法用的.
2.UCAppDelegateReduce.這個小工具依賴上面的UCRuntimeKit來做消息轉(zhuǎn)發(fā).
實現(xiàn)原理
1.先將項目中的delegate與框架中的
UCAppDelegateRealize實現(xiàn)的22個方法進行交換,如果appdelegate沒實現(xiàn)這個方法則不會交換,交換完成后不影響之前的邏輯,依舊會先調(diào)用原先appdelegate的邏輯,如果這22個方法沒有包含你需要轉(zhuǎn)發(fā)給組件的方法的話支持擴展.2.當delegate接收到調(diào)用時,會自動來到
UCAppDelegateRealize,這里在會根據(jù)位移枚舉的配置來對各個組件調(diào)用,這個調(diào)用過程依賴UCRuntimeKit,十分安全,不會crash.
使用
可以利用cocoapod進行導入,pod 'UCAppDelegateReduce'
Objc中的使用
1.新建一個Objc類,例如我這里取名叫
AppDelegateExchange-
2.在load類方法里進行下面的配置,就可以了
+ (void)load { UCAppDelegateMethodExchangeManager *manager = [UCAppDelegateMethodExchangeManager share]; // sendMessageType 是位移枚舉,可以選擇自己想給子模塊派發(fā)的方法 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類,例如我這里取名叫
AppDelegateExchange2.要轉(zhuǎn)發(fā)的Module中的appdelegate方法前要加
@objc,否則不支持動態(tài)調(diào)用-
3.在load類方法里進行下面的配置,就可以了
+ (void)load { UCAppDelegateMethodExchangeManager *manager = [UCAppDelegateMethodExchangeManager share]; // 這里Objc調(diào)用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是很靈活的,支持位移枚舉配置,配置后不會調(diào)用未配置的方法,另外manager的配置在app的生命周期中只應(yīng)該在最開始load的時候配置一次!配置完成后這里會解析,生成類似這樣的map,以代理方法名為key,需要轉(zhuǎn)發(fā)的類名集合為value,并將這個map緩存在內(nèi)存中,方便快速轉(zhuǎn)發(fā)給各個組件.
這樣你就可以把例如原先寫在appdelegate中的開屏配置,分享key配置,支付配置,push路由配置,3Dtouch等等直接寫在各自的模塊中了,這里的調(diào)用順序也是可以通過配置來決定的.
但是如果這個調(diào)用是異步的,例如組件B的一個功能依賴組件B的回調(diào),建議還是把這個寫在組件a的delegate實現(xiàn)里.
做完了這些你會發(fā)現(xiàn)你原來的delegate基本可以什么都不寫了,他已經(jīng)把業(yè)務(wù)分散到各個組件中去了.
UT
關(guān)于單元測試,這里基本只是測試了調(diào)用這個模塊的,轉(zhuǎn)發(fā)各個模塊都是手動測得,判斷參數(shù)能傳入到各個組件就沒有更深度的寫了,這里的單元測試確實不太好寫.