架構(gòu)之路 (三) —— APP架構(gòu)之網(wǎng)絡(luò)層分析(一)

版本記錄

版本號 時間
V1.0 2018.05.19

前言

前面寫了那么多篇主要著眼于局部問題的解決败砂,包括特定功能的實現(xiàn)腕巡、通用工具類的封裝造虎、視頻和語音多媒體的底層和實現(xiàn)以及動畫酷炫的實現(xiàn)方式等等声邦。接下來這幾篇我們就一起看一下關(guān)于iOS系統(tǒng)架構(gòu)以及獨(dú)立做一個APP的架構(gòu)設(shè)計的相關(guān)問題虫几。感興趣的可以看上面幾篇豹爹。
1. 架構(gòu)之路 (一) —— iOS原生系統(tǒng)架構(gòu)(一)
2. 架構(gòu)之路 (二) —— APP架構(gòu)分析(一)

回顧

上一篇主要講述了一個APP的架構(gòu)分析和設(shè)計滑蚯,這一篇我們就說一下APP架構(gòu)中的網(wǎng)絡(luò)層俺附。


網(wǎng)絡(luò)層在APP中的地位

網(wǎng)絡(luò)層就是APP從服務(wù)器獲取信息的一個媒介和方式肥卡,沒有網(wǎng)絡(luò)層,可以說APP就是一潭死水事镣,有沒有沒有網(wǎng)絡(luò)層的APP存在呢步鉴?有,但是很少,比如一些不需要和服務(wù)器交互的APP就不需要網(wǎng)絡(luò)層氛琢,比如你做一個簡單的相機(jī)喊递,帶有各種濾鏡處理,也不需要注冊登錄等邏輯阳似,照完像就保存到本地骚勘,那么這個APP就不需要網(wǎng)絡(luò)層,但是極大多數(shù)APP都是需要網(wǎng)絡(luò)層的撮奏,有了網(wǎng)絡(luò)層你的APP才會“動起來”俏讹。


casa大牛對網(wǎng)絡(luò)層搭建的想法

關(guān)于網(wǎng)絡(luò)層的搭建,有很多大神的博客上都說的很多比如畜吊,Casa Taloyum的博客藐石。他主要說了三個問題,分別如下所示:

1. 網(wǎng)絡(luò)層跟業(yè)務(wù)對接部分的設(shè)計

網(wǎng)絡(luò)層跟業(yè)務(wù)層對接部分設(shè)計的好壞定拟,會直接影響到業(yè)務(wù)工程師實現(xiàn)功能時的心情。主要是圍繞下面三個問題進(jìn)行闡述的逗嫡。

使用哪種交互模式來跟業(yè)務(wù)層做對接

這里其實有兩個問題:

  • 以什么方式將數(shù)據(jù)交付給業(yè)務(wù)層青自?

這里casa大神建議使用Delegate為主,Notification為輔驱证,不建議使用block延窜,因為block容易因為循環(huán)引用造成對象無法釋放,在網(wǎng)絡(luò)回調(diào)中使用block抹锄,是block導(dǎo)致對象生命周期被延長的其中一個場合逆瑞,當(dāng)ViewController從window中卸下時,如果尚有請求帶著block在外面飛伙单,然后block里面引用了ViewController(這種場合非常常見)获高,那么ViewController是不能被及時回收的,即便你已經(jīng)取消了請求吻育,那也還是必須得等到請求著陸之后才能被回收念秧。然而使用delegate就不會有這樣的問題,delegate是弱引用布疼,哪怕請求仍然在外面飛摊趾,ViewController還是能夠及時被回收的,回收之后指針自動被置為了nil游两,無傷大雅砾层。

casa建議使用Notification使用情景在于網(wǎng)絡(luò)層網(wǎng)絡(luò)狀況變化的情況,例如2G到3G等方式的變化贱案。

  • 交付什么樣的數(shù)據(jù)給業(yè)務(wù)層肛炮?

網(wǎng)絡(luò)層數(shù)據(jù)交付這部分時,casa添加了reformer(名字而已,叫什么都好)這個對象用于封裝數(shù)據(jù)轉(zhuǎn)化的邏輯铸董,這個對象是一個獨(dú)立對象祟印,事實上,它是作為Adaptor模式存在的粟害。我們可以這么理解:想象一下我們洗澡時候使用的蓮蓬頭蕴忆,水管里出來的水是API下發(fā)的原始數(shù)據(jù)。reformer就是蓮蓬頭上的不同水流擋板悲幅,需要什么模式套鹅,就撥到什么模式。

是否有必要將API返回的數(shù)據(jù)封裝成對象然后再交付給業(yè)務(wù)層

作者的意見是需要將API返回的數(shù)據(jù)封裝成對象汰具,在交給業(yè)務(wù)層的卓鹿。

使用集約化調(diào)用方式還是離散型調(diào)用方式去調(diào)用API

集約型API調(diào)用其實就是所有API的調(diào)用只有一個類,然后這個類接收API名字留荔,API參數(shù)吟孙,以及回調(diào)著陸點(可以是target-action,或者block聚蝶,或者delegate等各種模式的著陸點)作為參數(shù)杰妓。然后執(zhí)行類似startRequest這樣的方法,它就會去根據(jù)這些參數(shù)起飛去調(diào)用API了碘勉,然后獲得API數(shù)據(jù)之后再根據(jù)指定的著陸點去著陸巷挥。

集約型API調(diào)用方式:
[APIRequest startRequestWithApiName:@"itemList.v1" params:params success:@selector(success:) fail:@selector(fail:) target:self];

離散型API調(diào)用是這樣的,一個API對應(yīng)于一個APIManager验靡,然后這個APIManager只需要提供參數(shù)就能起飛倍宾,API名字、著陸方式都已經(jīng)集成入APIManager中胜嗓。比如這樣:

離散型API調(diào)用方式:
@property (nonatomic, strong) ItemListAPIManager *itemListAPIManager;
// getter
- (ItemListAPIManager *)itemListAPIManager
{
    if (_itemListAPIManager == nil) {
        _itemListAPIManager = [[ItemListAPIManager alloc] init];
        _itemListAPIManager.delegate = self;
    }
    return _itemListAPIManager;
}
// 使用的時候就這么寫:
[self.itemListAPIManager loadDataWithParams:params];

關(guān)于集約型的API調(diào)用和離散型的API調(diào)用高职,casa傾向于這樣:對外提供一個BaseAPIManager來給業(yè)務(wù)方做派生,在BaseManager里面采用集約化的手段組裝請求辞州,放飛請求初厚,然而業(yè)務(wù)方調(diào)用API的時候,則是以離散的API調(diào)用方式來調(diào)用孙技。如果你的App只提供了集約化的方式产禾,而沒有離散方式的通道,那么我建議你再封裝一層牵啦,便于業(yè)務(wù)方使用離散的API調(diào)用方式來放飛請求亚情。

2. 網(wǎng)絡(luò)層的安全機(jī)制實現(xiàn)

  • 判斷API的調(diào)用請求是來自于經(jīng)過授權(quán)的APP
  • 保證傳輸數(shù)據(jù)的安全
    • 建議使用HTTPS

3. 網(wǎng)絡(luò)層的優(yōu)化方案

網(wǎng)絡(luò)層的優(yōu)化手段主要從以下三方面考慮:

針對鏈接建立環(huán)節(jié)的優(yōu)化

  • 使用緩存手段減少請求的發(fā)起次數(shù)
  • 使用策略來減少請求的發(fā)起次數(shù)

針對鏈接傳輸數(shù)據(jù)量的優(yōu)化

傳輸?shù)臄?shù)據(jù)少了,那么自然速度就上去了哈雏。這里沒什么花樣可以講的楞件,就是壓縮唄衫生。

針對鏈接復(fù)用的優(yōu)化

建立鏈接本身是屬于比較消耗資源的操作,耗電耗時土浸。SPDY自帶鏈接復(fù)用以及數(shù)據(jù)壓縮的功能罪针,所以服務(wù)端支持SPDY的時候,App直接掛SPDY就可以了黄伊。如果服務(wù)端不支持SPDY泪酱,也可以使用PipeLine,蘋果原生自帶這個功能还最。


網(wǎng)絡(luò)層規(guī)范

這里另外一個牛人寫的也不錯墓阀,先把地址貼出來 —— iOS網(wǎng)絡(luò)層架構(gòu)設(shè)計分享

1. 網(wǎng)絡(luò)層接口規(guī)范

接口數(shù)據(jù)返回結(jié)構(gòu)

返回的是兩層三部分結(jié)構(gòu)code、msg拓轻、data

"code": 0,
"msg": "",
"data": {
        "upload_log": true,
        "has_update": false,
        "admin_id": "529ecfd64"
    }
  • code:錯誤碼斯撮,這個用來定義各種錯誤原因,方便客戶端進(jìn)行各種處理扶叉。
  • msg:接口文案提示勿锅,包括錯誤提示,用來直接顯示給用戶枣氧。
  • data:需要返回的數(shù)據(jù)溢十,可以是字典,可以是數(shù)組作瞄。

關(guān)于請求方式

一般都提供標(biāo)準(zhǔn)的GET/POST請求方式。

2. 多服務(wù)器多環(huán)境設(shè)置

為什么要多服務(wù)器環(huán)境危纫?標(biāo)準(zhǔn)的APP是有4個環(huán)境的宗挥,開發(fā)、測試种蝶、預(yù)發(fā)契耿、正式,特別是服務(wù)器的代碼螃征,不能說所有的代碼更改都在正式環(huán)境下搪桂。

3. 網(wǎng)絡(luò)請求的取消

當(dāng)一個頁面的請求正在天上飛的時候,用戶等了好久不耐煩了盯滚,小手點了個back踢械,然后ViewController被pop被回收。此時請求的著陸點就沒了魄藕。這是很危險的情況内列,著陸點要是沒了,就很容易crash的背率。

一般是按照下面方式進(jìn)行處理:使用了runtime话瞧,給ViewController添加一個字典嫩与,來保存requestID和BaseDataEngine,這樣對于ViewController來說就不是必須要寫變量來持有BaseDataEngine了交排。

在發(fā)起請求的時候進(jìn)行綁定

[control.networkingAutoCancelRequests setEngine:self requestID:self.requestID];

在請求完成的時候進(jìn)行刪除

[weakControl.networkingAutoCancelRequests removeEngineWithRequestID:engine.requestID];

我自己關(guān)于網(wǎng)絡(luò)層架構(gòu)的看法

  • 現(xiàn)在絕大多數(shù)APP都不會自己封裝NSURLSession進(jìn)行網(wǎng)絡(luò)下載划滋,基本都是基于AFNetworking的二次開發(fā)的。因此埃篓,很多關(guān)于網(wǎng)絡(luò)的問題处坪,轉(zhuǎn)化為了對AFNetworking進(jìn)行二次封裝的優(yōu)劣的問題。我待過的公司都许,我見過封裝后用delegate回調(diào)數(shù)據(jù)的稻薇,也見過用block回調(diào)數(shù)據(jù)的,他們各有優(yōu)劣胶征。用deleagate回調(diào)數(shù)據(jù)的塞椎,可以說很麻煩,代碼很分散睛低,你要在請求的VC里面設(shè)置delegate案狠,還有實現(xiàn)代理方法,優(yōu)點就是弱引用钱雷,不會引起循環(huán)引用造成VC釋放了骂铁,請求還在飛的情況。block代碼就比較集中了罩抗,處理起來很簡明拉庵,但是容易引起retain,這個是需要注意的問題套蒂。

  • 對于AFNetworking的二次封裝钞支,建議抽象出一個BaseService,然后業(yè)務(wù)方根據(jù)不同host和需求應(yīng)用場景操刀,分離出自己的service子類烁挟,然后請求和鏈接網(wǎng)絡(luò)層。

  • 關(guān)于網(wǎng)絡(luò)層回來的數(shù)據(jù)骨坑,我建議也是采用reformer的形式比較好撼嗓,根據(jù)不同的需求可以直接返回不同的數(shù)據(jù),只需更改淋浴的出水口的蓮蓬頭就可以出不同形式的水欢唾。

參考文章

1. iOS應(yīng)用架構(gòu)談 網(wǎng)絡(luò)層設(shè)計方案
2. iOS網(wǎng)絡(luò)層架構(gòu)設(shè)計分享
3. iOS網(wǎng)絡(luò)架構(gòu)文檔整理
4. iOS網(wǎng)絡(luò)架構(gòu)文檔整理

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末且警,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子礁遣,更是在濱河造成了極大的恐慌振湾,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件亡脸,死亡現(xiàn)場離奇詭異押搪,居然都是意外死亡树酪,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進(jìn)店門大州,熙熙樓的掌柜王于貴愁眉苦臉地迎上來续语,“玉大人,你說我怎么就攤上這事厦画〈眩” “怎么了?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵根暑,是天一觀的道長力试。 經(jīng)常有香客問我,道長排嫌,這世上最難降的妖魔是什么畸裳? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮淳地,結(jié)果婚禮上怖糊,老公的妹妹穿的比我還像新娘。我一直安慰自己颇象,他們只是感情好伍伤,可當(dāng)我...
    茶點故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著遣钳,像睡著了一般扰魂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蕴茴,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天劝评,我揣著相機(jī)與錄音,去河邊找鬼荐开。 笑死付翁,一個胖子當(dāng)著我的面吹牛简肴,可吹牛的內(nèi)容都是我干的晃听。 我是一名探鬼主播,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼砰识,長吁一口氣:“原來是場噩夢啊……” “哼能扒!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起辫狼,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤初斑,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后膨处,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體见秤,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡砂竖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了鹃答。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片乎澄。...
    茶點故事閱讀 39,731評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖测摔,靈堂內(nèi)的尸體忽然破棺而出置济,到底是詐尸還是另有隱情,我是刑警寧澤锋八,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布浙于,位于F島的核電站,受9級特大地震影響挟纱,放射性物質(zhì)發(fā)生泄漏羞酗。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一樊销、第九天 我趴在偏房一處隱蔽的房頂上張望整慎。 院中可真熱鬧,春花似錦围苫、人聲如沸裤园。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拧揽。三九已至,卻和暖如春腺占,著一層夾襖步出監(jiān)牢的瞬間淤袜,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工衰伯, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留铡羡,地道東北人。 一個月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓意鲸,卻偏偏與公主長得像烦周,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子怎顾,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,629評論 2 354

推薦閱讀更多精彩內(nèi)容