AppDelegate的模塊化+瘦身

前言

關于iOS的模塊化,要追溯到16年接觸的BeeHive了,BeeHive將功能模塊化,以module的形式進行構建,以performSelector:的形式進行module的事件響應,以protocol的形式進行module間的通信。可以說思路非常清晰明了了。關于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;
}
復制代碼

沒看錯,這樣一搞AppDelegateapplication: 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])就會執行completemodulesel返回,也就是到了AppDelegate里面,繼而執行modulesel函數,并且將參數傳遞過去。

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?。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/275919.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/275919.shtml
英文地址,請注明出處:http://en.pswp.cn/news/275919.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

yii mysql_Yii2框架操作數據庫的方法分析【以mysql為例】

本文實例講述了Yii2框架操作數據庫的方法。分享給大家供大家參考&#xff0c;具體如下&#xff1a;準備數據庫DROP TABLE IF EXISTS pre_user;CREATE TABLE pre_user(id int(11) AUTO_INCREMENT PRIMARY KEY,username varchar(255) NOT NULL,password varchar(32) NOT NULL DEF…

C++接口注意

1. 用Record接口&#xff0c;要注意 Packed的區別 2. cdecl和stdcall的區別 3. C導出的函數建議用C格式stdcall導出&#xff0c;使用Def文件定義名稱 4. 用VS寫的API dll要注意是否引用了MFC的DLL&#xff0c;否則會使LoadLibrary失敗&#xff0c;并GetLastError后返回14001 Ap…

Vue 3.1.0 的 beta 版發布

大家好&#xff0c;我是若川&#xff08;點這里加我微信 ruochuan12&#xff0c;長期交流學習&#xff09;。昨晚尤大視頻號直播說到vue 3.1.0 beta版發布了&#xff0c;今天分享這篇文章。也有小伙伴可能注意到了昨晚我一直在送禮物。點擊下方卡片關注我、加個星標&#xff0c…

設計模式練習_設計練習是邪惡的

設計模式練習It was the final round of interviews. Or, so the candidate thought.這是采訪的最后一輪。 或者&#xff0c;所以候選人認為。 She’d spent all day interviewing in our office. As the final interviewer, I walked her out the building. She seemed confi…

morningcat2018 LearningDocs

2019獨角獸企業重金招聘Python工程師標準>>> LearningDocs 學習資料與文檔 JCP&#xff08;Java Community Process &#xff0c;Java社區進程 &#xff09; https://www.jcp.org/en/home/index JSR&#xff08;Java Specification Requests&#xff0c;Java規范請求…

firefox下可惡的value

前幾天做項目 遇到這樣一個情況 document.getElementById("txtTest").value "111"; 這條語句在ff下和ie下都是好用的 但是用開發工具看html代碼 ie下顯示正常 ff下顯示的卻是修改之前的(實際上已經修改了&#xff0c;只是html沒有修改過來) 用js修改input…

據說 99% 的人不知道 vue-devtools 還能直接打開對應組件文件?本文原理揭秘

1. 前言你好&#xff0c;我是若川[1]&#xff0c;微信搜索「若川視野」關注我&#xff0c;專注前端技術分享&#xff0c;一個愿景是幫助5年內前端開闊視野走向前列的公眾號。歡迎加我微信ruochuan12&#xff0c;長期交流學習。這是學習源碼整體架構系列 之 launch-editor 源碼&…

mysql 存儲 事務_MYSQL 可以在存儲過程里實現事務控制嗎

展開全部6.7 MySQL 事務與鎖定命令6.7.1 BEGIN/COMMIT/ROLLBACK 句法缺省的&#xff0c;MySQL 運行在 autocommit 模式。這就意味著&#xff0c;當你執行完一e69da5e887aa62616964757a686964616f31333361326265個更新時&#xff0c;MySQL 將立刻將更新存儲到磁盤上。如果你使用…

如何忽略證書繼續訪問_前5個最容易被忽視的可訪問性問題

如何忽略證書繼續訪問Accessibility is quickly becoming one of the most important aspects of the way we use the web, if not the most important. Just between 2017 and 2018, the number of federal court cases regarding web accessibility nearly tripled, signifyi…

《認清C++語言》のrandom_shuffle()和transform()算法

1&#xff09;STL中的函數random_shuffle()用來對一個元素序列進行重新排序&#xff08;隨機的&#xff09;&#xff0c;函數原型如下&#xff1a; template<class RandomAccessIterator> void random_shuffle( RandomAccessIterator _First, //指向序列首元素的迭代器 R…

作為前端開發,如何高效學習 TypeScript

大家好&#xff0c;我是若川。有朋友跟我說最近面試前端候選人&#xff0c;問到關于 JavaScript 的一些少見誤區問題&#xff0c;候選人很多都沒回答上來&#xff0c;他很詫異&#xff0c;一個從國際大廠出來的面試者&#xff0c;竟然對 JavaScript 的一些誤區問題都不了解。他…

figma下載_對于這10家公司,Figma是邁向新高度的起點

figma下載Hey everyone! In this post, we are highlighting 10 companies for which the use of Figma has become the starting point on the path to new heights. These are the use cases of problems and their solutions, where Figma played a decisive role.嘿大家&am…

mysql查詢條件為or_使用mysql查詢where條件里的or和and

為什么要著重講這塊內容呢?因為好多小伙伴都會混淆&#xff0c;要不就是不知道怎么組合使用&#xff0c;今天就給大家講這部分內容干貨&#xff0c;讓大家半分鐘看懂。AND、OR運算符的組合使用在WHERE子句中&#xff0c;通過AND、OR運算符可以同時連接多個條件&#xff0c;當然…

sql server(常用)

普通用法 //生成 uuid 并轉為小寫 select LOWER(SUBSTRING(uuid,1,8)-SUBSTRING(uuid,10,4)-SUBSTRING(uuid,15,4)-SUBSTRING(uuid,20,4)-SUBSTRING(uuid,25,12)) from (select cast(NEWID() as varchar(36)) as uuid) s //ea52a7bb-a2aa-44b8-be28-5ebc64defcf9//獲取時分秒…

代碼編寫中會遇到的安全性問題

一、常用的攻擊手段 1&#xff0e;腳本注入 漏洞描述&#xff1a; 腳本注入攻擊在通過瀏覽器使用用戶輸入框插入惡意標記或腳本代碼時發生。 如&#xff1a;某個輸入框允許用戶向數據存儲中插入內容&#xff0c;如果將一段js腳本插入其中&#xff0c;則當其他用戶使用或瀏覽此數…

TypeScript 原來可以這么香?!

先問一個問題&#xff0c;JavaScript有幾種數據類型&#xff1f;number、string、boolean、null、undefined、symbol、bigint、object其中 bigint 是 ES2020 新增的數據類型&#xff0c;而早在 TS3.2 時便成為 TS 的標準&#xff0c;其實還有好多 ES 標準是 TS 率先提出的&…

java8新特性stream深入解析

2019獨角獸企業重金招聘Python工程師標準>>> 繼續java8源碼的發燒熱&#xff0c;越看越是有充實的感覺。 數據時代下的產物 Java順應時代的發展推出的高效處理大量數據能力的api&#xff0c;它專注于對集合對象進行各種非常便利、高效的聚合操作&#xff0c;借助于同…

mysql內連接的自連接_mysql 內連接、外連接、自連接

一)內連接(等值連接)&#xff1a;查詢客戶姓名&#xff0c;訂單編號&#xff0c;訂單價格---------------------------------------------------select c.name,o.isbn,o.pricefrom customers c inner join orders owhere c.id o.customers_id;-------------------------------…

關于ASP.NET MVC

我是否要學習一下ASP.NET MVC呢&#xff1f;因爲從它剛發布的時候就已經初步的學習了一下&#xff0c;可是一直沒有堅持下來。不過心里對于這份惦記&#xff0c;又讓我始終放不下&#xff0c;看來應該抽個時間來系統的學習一下。 就這樣吧&#xff0c;把自己的博客當成微博來使…

版式設計與創意 pdf_戀愛與版式

版式設計與創意 pdfSince its beginnings, Libe?ration has been characterized by a very distinctive use of typeface, to such an extent that Libe? has put its mark on fonts from across different eras, appropriating these in a certain way.小號因斯它的起點&…