AppDelegate的模块化+瘦身
前言
關于iOS的模塊化,要追溯到16年接觸的BeeHive了,BeeHive將功能模塊化,以module的形式進行構建,以performSelector:的形式進行module的事件響應,以protocol的形式進行module間的通信??梢哉f思路非常清晰明了了。關于BeeHive的代碼傳送門alibaba/BeeHive,star已3.2k,關于BeeHive源碼解析可參考霜神文章傳送門BeeHive —— 一個優雅但還在完善中的解耦框架。實際上我并不認為BeeHive可以真正用到我們項目中來,它確實構建了module,但是module實例帶來的內存問題會讓人頭疼。個人認為將BeeHive思想中的module部分改造一下用在我們的AppDelegate中是完全可行的。下面進入正文。
目錄
一、模塊拆分
二、模塊事件響應
三、模塊管理
-
1.模塊注冊
-
2.觸發event
-
3.移除module
四、總結
一、模塊拆分
畫了一個結構圖,module1到module4為我們需要在Appdelegate中進行處理的業務邏輯,比如說我們的數據庫處理,分享功能,推送功能等等。
首先為所有模塊定義了三個接口: @protocol SHRMAppEventModuleProtocol <UIApplicationDelegate>- (NSInteger)moduleLevel; - (void)destroyModule; - (NSString *)moduleID;@end 復制代碼接口定義了三個函數,moduleLevel返回module執行的優先級,destroyModule用來對module進行釋放,moduleID返回當前module的id。接口的默認實現統一在BaseAppEventModule中進行。BaseAppEventModule為所有module的父類,只有繼承了BaseAppEventModule的module才能被管理。
關于BaseAppEventModule的默認實現也很簡單,對module進行銷毀的時候用到了SHRMAppEventModuleManager下面會講到,優先級默認設置100.
@interface SHRMBaseAppEventModule : NSObject <SHRMAppEventModuleProtocol>@end#define MODULE_LEVEL_DEFAULT 100 @implementation SHRMBaseAppEventModule- (NSInteger)moduleLevel {return MODULE_LEVEL_DEFAULT; }- (void)destroyModule {[[SHRMAppEventModuleManager sharedInstance] removeModule:[self moduleID]];NSLog(@"%@ destroy",NSStringFromClass([self class])); }- (NSString *)moduleID {return NSStringFromClass([self class]); }@end 復制代碼模塊的創建上面說到了必須要繼承自SHRMBaseAppEventModule,只有繼承了SHRMBaseAppEventModule的module才會被管理,因為只有SHRMBaseAppEventModule遵循了SHRMAppEventModuleProtocol協議。關于module創建部分:
@interface testMudule : SHRMBaseAppEventModule @end@implementation testMudule- (NSInteger)moduleLevel {return 1; }- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {[self initMudule];[self destroyModule];return YES; }- (void)initMudule {NSLog(@"testMudule init"); }@end 復制代碼application: didFinishLaunchingWithOptions:函數的實現展示了一個module的整個生命周期,從創建到銷毀的過程,那么application: didFinishLaunchingWithOptions:是怎么響應的,實際上module的頭文件并沒有暴漏任何接口,到這里就實現了功能的模塊化。那為什么還能執行到這里,這要感謝強大的runtime函數performSelector:,下面講一下我對module事件響應的處理。
二、模塊事件響應
還是以上面的application: didFinishLaunchingWithOptions:函數為例,它是怎么來的,很明顯這是AppDelegate里面的APP生命周期回調:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {[[SHRMAppEventModuleManager sharedInstance] handleApplicationEvent:@selector(application:didFinishLaunchingWithOptions:)Complete:^(id _Nonnull module, SEL _Nonnull sel) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks"[module performSelector:selwithObject:applicationwithObject:launchOptions]; #pragma clang diagnostic pop}];return YES; } 復制代碼沒看錯,這樣一搞AppDelegate的application: didFinishLaunchingWithOptions:就剩這些了,這樣一來,所有實現了application: didFinishLaunchingWithOptions:的modlue都會被調用,調用優先級根據接口定義的moduleLevel返回值確定。到這里我們就完成了AppDelegate瘦身的工作,實際上AppDelegate中的其他回調處理是一樣的。當然還有一個很重要的沒有說,就是SHRMAppEventModuleManager做了什么,通過上面的結構圖能夠看到SHRMAppEventModuleManager是個中間件,用來處理module與AppDelegate間的關系。下面說到第三部分,模塊管理。
三、模塊管理
SHRMAppEventModuleManager為一個單例,提供了三個接口:
/**初始化所有的AppDelegate相關的Event Modules*/ - (void)registedAllModules;/**觸發event module處理AppDelegate回調事件@param eventSel AppDelegate 回調事件消息@param complete module處理handle*/ - (void)handleApplicationEvent:(SEL)eventSelComplete:(void(^)(id module,SEL sel))complete;/**移除module對象@param moduleID module ID*/ - (void)removeModule:(NSString *)moduleID; 復制代碼1.模塊注冊
模塊注冊的思路是完全按照BeeHive的思想來的,在編譯期就將我們的module通過__attribute函數進行注冊。在運行期再將我們注冊好的module取出來在registedAllModules中進行實例化,按照level的返回值進行排序存儲。__attribute函數具體做了什么可以參考我之前的文章寫一個易于維護使用方便性能可靠的Hybrid框架(三)—— 配置插件關于插件注冊部分的解釋。
2.觸發event
handleApplicationEvent:Complete:為module事件響應的核心函數:
- (void)handleApplicationEvent:(SEL)eventSelComplete:(void(^)(id module,SEL sel))complete {NSMutableArray *tmpAppEventModules = [[NSMutableArray alloc] initWithArray:self.appEventModules];for (id<SHRMAppEventModuleProtocol>module in tmpAppEventModules){if ([module conformsToProtocol:@protocol(SHRMAppEventModuleProtocol)]){if ([module respondsToSelector:eventSel]) {if (complete) {complete(module,eventSel);}}}} } 復制代碼if ([module respondsToSelector:eventSel])就會執行complete將module和sel返回,也就是到了AppDelegate里面,繼而執行module的sel函數,并且將參數傳遞過去。
3.移除module
module的移除,在AppDelegate里面,我們將程序啟動之后調用完就不再使用的功能module會手動執行移除操作。這也是前言所說的BeeHive在module移除這一塊會稍顯復雜,但是在AppDelegate里面,我們是完全可以知道哪些module在加載之后可以立即移除的,另外我們僅在AppDelegate中進行模塊化,產生的module實例也會非常少,so,完全沒必要擔心module所帶來的內存開銷問題。
- (void)removeModule:(NSString *)moduleID {NSInteger index = NSNotFound;NSInteger resIndex = 0;for (id<SHRMAppEventModuleProtocol>module in self.appEventModules){if ([[module moduleID] isEqualToString:moduleID]){index = resIndex;break;}resIndex++;}if (index != NSNotFound) {[self.appEventModules removeObjectAtIndex:index];} } 復制代碼總結
最后總結一下,關于模塊化,現在總體來看比較流行,也有很多介紹模塊化,組件化具體實施之路的文章,都很優秀,也值得學習。關于解耦,我更傾向于protocol的方式,接口protocol化,代碼易讀且清晰。之前看過mrpeak在組件化方面的文章,傳送門iOS 組件化方案,個人覺得protocol+version的方案和BeeHive非常像,protocol解耦,version進行module的版本管理,但是還是沒有解決module所帶來的內存開銷問題,module一旦細化,何時銷毀也是讓開發者頭疼的問題。先說這么多,各位小伙伴有任何問題歡迎評論區討論。
最后附上DEMO傳送門:AppDelegateMudule,歡迎star?。
總結
以上是生活随笔為你收集整理的AppDelegate的模块化+瘦身的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ubuntu下使用锐捷客户端链接校园网
- 下一篇: (转载)Tuxedo中间件简介