最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

iOS模塊化開發(fā)淺析

 更新時間:2018年04月21日 09:05:49   投稿:laozhang  
本文給大家分析了IOS在模塊發(fā)開發(fā)時候的相關注意點以及簡單代碼做了分享,有興趣的朋友參考學習下。

背景:由于目前所在公司的iOS項目的依賴管理是比較原始的狀態(tài),但是APP功能又是越來越復雜的,這就帶來的很多問題,比如開發(fā)時編譯時間過長、模塊間耦合嚴重、模塊依賴混亂等。最近又聽說這個項目中的部分功能可能需要獨立出一個新APP,本著“Don't repeat yourself”的原則,我們試著抽離出原項目中的各個模塊,并在新的APP中集成這些模塊。

最近算是初步完成了新APP的模塊化,也算是從中總結了一些經(jīng)驗拿出來分享一下。同時也完成了一個模塊化框架TinyPart歡迎star。

模塊劃分

做模塊化還是要結合實際業(yè)務,對目前APP的功能做一個模塊劃分,在劃分模塊的時候還需要關注模塊之間的層級。

比如說,在我們項目中,模塊被分成了3個層級:基礎層、中間層、業(yè)務層?;A層模塊比如像網(wǎng)絡框架、持久化、Log、社交化分享這樣的模塊,這一層的模塊我們可以稱之為組件,具有很強的可重用性。中間層模塊可以有登錄模塊、網(wǎng)絡層、資源模塊等,這一層模塊有一個特點是它們依賴著基礎組件但又沒有很強的業(yè)務屬性,同時業(yè)務層對這層模塊的依賴是很強的。業(yè)務層模塊,就是直接和產(chǎn)品需求對應的模塊了,比如類似朋友圈、直播、Feeds流這樣的業(yè)務功能了。

代碼隔離

模塊化首先要做的是代碼層面上獨立,任意一個基礎模塊都是可以獨立編譯的,底層模塊絕對不能有對上層模塊的代碼依賴,還要確保未來也不會再出現(xiàn)這樣的代碼。

在這里我們選擇使用CocoaPods來確保模塊間代碼隔離,基礎和中間層模塊是一定會做成標準的私有pods組件,加入到私有pods倉庫。業(yè)務層的模塊,則不一定非要加到私有pods倉庫中,也可以使用submodule + local pods的方案。這樣做有兩個原因:其一是業(yè)務模塊的改動往往比較頻繁,如果是標準的私有pods組件則需要頻繁的操作pod install或者pod update;其二是如果是local pod會直接引用對應倉庫的源文件,在主工程對pods工程下業(yè)務模塊的改動就是直接對其git倉庫的改動,沒有了頻繁的pod repo push和pod install操作。

依賴管理

選擇使用CocoaPods另外一個重要原因就是,可以通過它來管理模塊間的依賴,之前項目各個功能之所以難以復用的重要原因之一就是沒有聲明依賴。這里的依賴不僅僅是A模塊依賴B模塊這樣的事情,還可以是A模塊運行需要的所有工程配置,比如A模塊工程需要添加一個GCC_PREPROCESSOR_DEFINITIONS預處理宏才能正常編譯。因此,個人認為模塊依賴聲明非常重要,即便沒有像CocoaPods這樣的管理工具,也應該有相關文檔來說明每個內(nèi)部模塊或者SDK的依賴。

CocoaPods的方便之處就在于你必須把你模塊的依賴列出來,否則是無法通過pod spec lint過程的,并且所有的依賴項也都是必須是pods倉庫。除此以外,依賴的集成也是自動化的,CocoaPods可以自動地添加工程配置和依賴組件。

模塊集成

在完成上述兩個步驟以后,模塊化工程的構建工作基本就結束了,接下來我們探討一下如何在工程中更好地使用這些模塊。為此我們寫了一個組件化的開源方案 TinyPart。

一般來說,模塊初始化需要在APP啟動或者UI初始化附近的時機來完成,有時候各個模塊的啟動順序可能也是有講究的,這些初始化邏輯我們往往會加入到AppDelegate這個類里。過一段時間我們會發(fā)現(xiàn),AppDelegate這個類變得臃腫不堪,邏輯復雜,難以維護。在TinyPart中,Module的聲明協(xié)議包含了UIApplicationDelegate,這就意味著每一個模塊都可以實現(xiàn)有一套自己的UIApplicationDelegate協(xié)議,并且它們之間調用順序是可以自定義的。

@interface TPLShareModule : NSObject <TPModuleProtocol>
@end
@implementation TPLShareModule
TP_MODULE_ASYNC

TP_MODULE_PRIORITY(TPLSHARE_MODULE_PRIORITY)

- (void)moduleDidLoad:(TPContext *)context {
  [WXApi registerApp:APPID];
}

- (BOOL)application:(UIApplication *)application
      openURL:(NSURL *)url
 sourceApplication:(NSString *)sourceApplication
     annotation:(id)annotation {
  return [WXApi handleOpenURL:url delegate:self];
}

- (BOOL)application:(UIApplication *)app
      openURL:(NSURL *)url
      options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
  return [WXApi handleOpenURL:url delegate:self];
}
@end

上面的代碼是一個微信社交分享模塊的初始化內(nèi)容,同時實現(xiàn)了微信分享所要求的UIApplicationDelegate中的方法。

通信

消息

在面向對象中,消息是一個十分重要的概念,它是對象之前通信的重要方式。但是,在OC中如果想要向一個對象發(fā)消息,正常做法就是將改對象類的頭文件import進來,這樣我們就能夠寫出[aInstance method]這樣的代碼了。

然而在模塊化中,我們并不希望模塊與模塊之間相互引用各自的類文件,但是又想要實現(xiàn)通信,那怎么辦呢?通過協(xié)議來完成。我們知道OC是一個動態(tài)語言,方法的調用過程其實是動態(tài)的,頭文件中消息方法的聲明只是為了通過編譯前的靜態(tài)檢查。也就是說,我們只要寫一個協(xié)議來告訴編譯器有這么一個方法就可以了,至于實際上究竟有沒有這個方法是在消息發(fā)過去以后就知道了。既然OC有這個特性,我們甚至可以直接通過類名和方法名向一個對象發(fā)送消息,這其實就是網(wǎng)上大部分組件化路由的實現(xiàn)機制。

因此在TinyPart中我們既提供了協(xié)議和路由兩種模式來調用模塊內(nèi)的服務。

@protocol TestModuleService1 <TPServiceProtocol>
- (void)function1;
@end

@interface TestModuleService1Imp : NSObject <TestModuleService1>
@end

@implementation TestModuleService1Imp
TPSERVICE_AUTO_REGISTER(TestModuleService1) // Service will be registered in "+load" method

- (void)function1 {
  NSLog(@"%@", @"TestModuleService1 function1");
}
@end

上面的代碼中,我們定義了一個服務的協(xié)議。

#import "TestModuleService1.h"

id<TestModuleService1> service1 = [[TPServiceManager sharedInstance] serviceWithName:@"TestModuleService1"];

[service1 function1];

這里我們只需要import上述協(xié)議的頭文件,然后就可以向TestModuleService1發(fā)消息了。

我們看到上述的跨模塊調用方案中,只需要暴露一個協(xié)議文件就可以了,下面我們再看一下如何用路由的方式來做到完全不暴露任何頭文件。

#import "TPRouter.h"

@interface TestRouter : TPRouter
@end

@implementation TestRouter
TPROUTER_METHOD_EXPORT(action1, {
  NSLog(@"TestRouter action1 params=%@", params);
  return nil;
});

TPROUTER_METHOD_EXPORT(action2, {
  NSLog(@"TestRouter action2 params=%@", params);
  return nil;
});
@end

在這里我們參考了ReactNative的方案,通過一個TPROUTER_METHOD_EXPORT宏來定義一個可供調用的路由服務,同時可以傳一個params參數(shù)進了。然后我們再來調用這個路由。

[[TPMediator sharedInstance] performAction:@"action1" router:@"Test" params:@{}];

通知

除了上面提到的兩種普通的模塊通信方案,我們發(fā)現(xiàn)在項目中經(jīng)常會有跨模塊的NSNotification,對于這樣的觀察者模式使用NSNotification來實現(xiàn)是最便捷的方式了。盡管NSNotification可以做到模塊間解耦,但是對于通知的管理過于松散會導致散落在各個模塊的NSNotification邏輯變得十分復雜,因此我們?yōu)門inyPart增加了一種有向通信的方案。

所謂有向通信,則是在NSNotification基礎上對通知的傳播方向進行了限制,底層模塊對上層模塊的通知稱為廣播Broadcast,上層模塊對底層模塊或者同層模塊的通知稱為上報Report。這樣做有兩個好處:一方面更利于通知的維護,另一方面可以幫助我們劃分模塊層級,如果我們發(fā)現(xiàn)有一個模塊需要向多個同級模塊進行Report那么這個模塊很有可能應該被劃分到更底層的模塊。

用法同NSNotification類似,只不過創(chuàng)建通知的方法是一個鏈式調用,大概就是這樣:

// 發(fā)送
TPNotificationCenter *center2 = [TestModule2 tp_notificationCenter];

[center2 reportNotification:^(TPNotificationMaker *make) {
  make.name(@"report_notification_from_TestModule2");
} targetModule:@"TestModule1"];
  
[center2 broadcastNotification:^(TPNotificationMaker *make) {
  make.name(@"broadcast_notification_from_TestModule2").userInfo(@{@"key":@"value"}).object(self);
}];

// 接收
TPNotificationCenter *center1 = [TestModule1 tp_notificationCenter];
[center1 addObserver:self selector:@selector(testNotification:) name:@"report_notification_from_TestModule2" object:nil];

相關文章

  • iOS 無卡頓同時使用圓角、陰影和邊框的實現(xiàn)

    iOS 無卡頓同時使用圓角、陰影和邊框的實現(xiàn)

    這篇文章主要介紹了iOS 無卡頓同時使用圓角、陰影和邊框的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-01-01
  • iOS中表單列表樣式鍵盤遮擋的解決方案

    iOS中表單列表樣式鍵盤遮擋的解決方案

    這篇文章主要給大家介紹了關于iOS中表單列表樣式鍵盤遮擋的解決方案,文中通過示例代碼將解決的方法一步步介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面來一起看看吧
    2019-01-01
  • iOS開發(fā)之路--仿網(wǎng)易抽屜效果

    iOS開發(fā)之路--仿網(wǎng)易抽屜效果

    本文是IOS開發(fā)之路系列的第一篇,主要講訴了如何仿網(wǎng)易新聞客戶端實現(xiàn)抽屜效果,全部源代碼都分享給大家,希望對大家有所幫助
    2014-08-08
  • iOS實現(xiàn)鎖屏頁面控制音樂播放

    iOS實現(xiàn)鎖屏頁面控制音樂播放

    這篇文章主要為大家詳細介紹了iOS實現(xiàn)鎖屏頁面控制音樂播放,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • react-native中AsyncStorage實例詳解

    react-native中AsyncStorage實例詳解

    這篇文章主要介紹了react-native中AsyncStorage實例詳解的相關資料,需要的朋友可以參考下
    2017-03-03
  • iOS10全新推送功能實現(xiàn)代碼

    iOS10全新推送功能實現(xiàn)代碼

    這篇文章主要為大家詳細介紹了iOS10全新推送功能實現(xiàn)代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-09-09
  • ios觸屏事件指南

    ios觸屏事件指南

    這篇文章主要給大家總結介紹了2種實現(xiàn)ios觸屏事件的方法,簡單實用,有需要的小伙伴可以參考下。
    2015-05-05
  • iOS獲取本地音頻文件(屬性/信息)

    iOS獲取本地音頻文件(屬性/信息)

    這篇文章主要為大家詳細介紹了iOS獲取本地音頻文件,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • IOS使用NSUserDefault去實現(xiàn)界面?zhèn)髦岛蛿?shù)據(jù)存儲

    IOS使用NSUserDefault去實現(xiàn)界面?zhèn)髦岛蛿?shù)據(jù)存儲

    這篇文章主要介紹了IOS使用NSUserDefault去實現(xiàn)界面?zhèn)髦岛蛿?shù)據(jù)存儲的相關資料,需要的朋友可以參考下
    2017-07-07
  • ios12中遇到的帶input彈窗的錯位問題的解決方法

    ios12中遇到的帶input彈窗的錯位問題的解決方法

    這篇文章主要介紹了ios12中遇到的帶input彈窗的錯位問題的解決方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-05-05

最新評論

广德县| 基隆市| 普安县| 柳河县| 元朗区| 榕江县| 玉龙| 崇义县| 莱芜市| 怀仁县| 台湾省| 东乡| 桂东县| 如皋市| 女性| 鹤山市| 咸丰县| 彭州市| 青阳县| 林芝县| 佛学| 临洮县| 揭阳市| 乐平市| 石渠县| 富源县| 元氏县| 三河市| 临邑县| 绥化市| 启东市| 呼伦贝尔市| 寻乌县| 格尔木市| 赫章县| 资阳市| 灵山县| 泸溪县| 广昌县| 阜阳市| 绥化市|