網(wǎng)絡(luò)層的參考姿勢

網(wǎng)絡(luò)是任何一個系統(tǒng)/平臺的基礎(chǔ)功能,在iOS上也同樣是這樣的.從NSURLConnectionNSURLSession,從ASIHttpRequest到目前最主流的AFNetworking.

事實上,一個項目中通常會有一個更高層次的封裝.可以是自行基于NSURLConnection進行封裝,也可以基于AFNetworking或者Alamofire.

這里提供一個參考的姿勢:ZCNetworking

結(jié)構(gòu)

主要提供了3層

  1. 網(wǎng)絡(luò)常用操作的抽象層:ZCNetworking,這里是基于AFNetworking
  2. 針對項目的具體操作Runner層:ZCApiRunner;提供大量的功能,配置以簡化項目中的實際使用.
  3. Actions:普通/上傳/下載操作的封裝;包括參數(shù)/url等,也提供了一些便利操作,比如好用的log.

抽象層

這是比較重要的一層,將網(wǎng)絡(luò)操作和具體實現(xiàn)隔離開來.僅僅暴露出一些task.

有了這一層,那么替換基礎(chǔ)庫就成為可能.ZCNetworking是基于AFNetworking,或許有一天會修改成其他的networking或者是直接使用NSURLSession呢?如果改動,只需要改動這一層即可,而整個項目不會受到任何影響.

這一層本身只提供幾個基礎(chǔ)方法:

  1. 數(shù)據(jù)獲取: sendRequest
  2. 上傳: uploadTask
  3. 下載:downloadFile;還包含了一個下載圖片的方法
  4. 一些基礎(chǔ)的操作方法,比如cookie等

基礎(chǔ)方法中也提供了2種形式,以方便配置:包含NSURLSessionConfiguration和不包含.當(dāng)然不包含則是默認.

暴露的接口較少,當(dāng)然完全可以根據(jù)實際需求進行擴充.不過需要確定的一點就是:接口完全和任意第三方類無關(guān).這樣才能使得替換底層實現(xiàn)與上層無關(guān).

接口的實現(xiàn)沒有太多要注意的.按照正常的AFNetworking使用即可.

Runner

這一層是針對于項目的具體實現(xiàn),做一些公共的配置/設(shè)置.包括:

  1. 區(qū)分正式/測試服務(wù)器
  2. 公共參數(shù)的處理,例如headers,params
  3. 對于邏輯成功/失敗的處理
  4. 對于數(shù)據(jù)獲取/上傳/下載的處理
  5. 對于batch操作的處理
  6. 對于chain操作的處理
服務(wù)器區(qū)分

通常項目會有至少2個以上的服務(wù)器,正式和測試服務(wù)器.而對于服務(wù)器地址的管理,有多種方式.可以是純手工的管理;可以是參數(shù)的配置,例如做一個宏;也可以做多個target;

純手工當(dāng)然不可取,太容易出錯.好吧..說的就是我..的確因為疏忽翻過這樣的錯誤.

配置本質(zhì)上也是純手工,只是設(shè)立了一個總開關(guān).但是一旦疏忽,仍然有風(fēng)險.

target會不會太heavy了點?假設(shè)還有cdn呢...

于是ZCNetworking中,根據(jù)當(dāng)前環(huán)境來自行決定使用的服務(wù)器:

- (void)startWithDebugDomain:(NSString *)debug releaseDomain:(NSString *)release {
    _debugDomain = debug;
    _releaseDomain = release;
}

- (NSString *)currentDomain {
    if (_forceDomain.length > 0) {
        return _forceDomain;
    }
    else {
#ifdef DEBUG
        return _debugDomain;
#else
        return _releaseDomain;
#endif
    }
}

其中還增加了一個forceDomain,可以強制使用某個環(huán)境,這樣便于調(diào)試.

公共參數(shù)

大多數(shù)項目會有這樣的需求.例如我這里會為每一個請求中加上這樣一組header:

headers[@"X-REQUESTED-WITH"] = @"1";

項目中也會需要公共參數(shù),例如每條api需要版本號和平臺等.

ZCNetworking在Runner中提供了相應(yīng)的接口:addtionalHeadersglobleParams.

邏輯判定

基礎(chǔ)網(wǎng)絡(luò)只能夠判定物理上是否成功.比如是否是http 200等.但是在很多時候,邏輯上的失敗也是失敗,應(yīng)該進入failure流程,不應(yīng)該進入success流程再進行判定.

例如登錄操作.用戶名密碼錯誤然后返回.此時物理上成功(http 200),但是邏輯上失敗.則應(yīng)當(dāng)進入失敗流程.

對于一些公共錯誤,可能會有公共的操作方式.例如token/cookie過期導(dǎo)致登錄失效,那么會彈出登錄UI等.

所以會有幾個操作:
codeKey/successCodes/warningCodes&&handler

codeKey則是返回字典的key

successCodes是個數(shù)組.如果返回字典的codekey字段的值滿足successCodes,則認為邏輯成功,否則邏輯失敗

warningCodes主要處理通用的錯誤,例如登錄失效.handler當(dāng)然就是處理的方式了.

是否邏輯成功完全依賴successCodes,和warningCodes無關(guān).

不過這需要服務(wù)端提供類似的邏輯才行,如果提供不了,不設(shè)置即可.將不會對返回的邏輯狀態(tài)進行處理,僅僅依賴物理狀態(tài).

請求的操作

一共就數(shù)據(jù)請求,上傳,下載三大類.對應(yīng)NSURLSessionDataTask/NSURLSessionUploadTask/NSURLSessionDownloadTask

利用之前的抽象層進行請求即可.不過請求內(nèi)容已經(jīng)被封裝成Action類型.包括url,params等東西.

當(dāng)物理狀態(tài)返回后,根據(jù)配置對邏輯狀態(tài)進行檢查(不檢查),最終返回相應(yīng)的數(shù)據(jù).

在請求中,有l(wèi)og是最方便的.以前關(guān)于調(diào)試,一般就2種方式:

  1. 斷點
  2. 使用工具,例如charles.

不過斷點不太方便,涉及到變量以及作用于的問題.針對個別問題還成,針對每一個請求都調(diào)試一翻,效率較低.

charles很好用,就是有點貴...

所以如果附帶log信息的話,可能性價比較高.ZCNetworking提供了一些log信息:

  1. url和參數(shù),以xxx.com/action?a=xx&b=xx的方式拼接,對于部分get請求可以直接用瀏覽器調(diào)用.
  2. method/header/params
  3. 對于error的log,包括物理和邏輯上的
  4. 返回值log,方便查看數(shù)據(jù)結(jié)構(gòu)

log信息由action中的參數(shù)showLog來控制.

batch

不算特別常用的功能.但似乎也有點用.

例如在一個頁面中,需要調(diào)用多條api才能將數(shù)據(jù)獲取完畢,然后渲染界面.當(dāng)然,這種方式顯然不太好,加入某條api出錯了呢?

在巧哥的YTKNetworking中也提供了同樣的功能.使用一個count進行計數(shù).當(dāng)請求返回,則在返回中count++.當(dāng)count等于請求的個數(shù),則執(zhí)行完畢.

ZCNetworking中,通過dispatch group處理這個功能.不過該功能有2個策略.
1.batch中一旦出錯,立刻停止,返回錯誤.
2.batch中一旦出錯,繼續(xù)執(zhí)行,最終返回一個字典.key為url,value為返回值.或許是object,或許是error.當(dāng)然如果都成功,則返回字典.key為url,value為object.

ZCNetworking選擇的是第一種策略.當(dāng)然你也可以選擇其他的策略.

chain

也不算特別常用的功能.也似乎有點用.

例如產(chǎn)品是必須先登錄->在獲取數(shù)據(jù).

YTKNetworking類似于遞歸的感覺,通過next index計數(shù),在請求完成后繼續(xù)執(zhí)行next,直到請求隊列完畢.

ZCNetworking中使用semaphore來處理chain,不過遇上了一個坑.

信號量是一個簡單的思路.類似于餐廳座位.有座位了就進入,沒座位了就等待.進入后,座位少一張,出來后座位多一張,下個人才能進.

然而,在創(chuàng)建了一個信號量以后,使用AFHTTPSessionManager發(fā)送get請求居然沒有反應(yīng)!而使用NSURLSession卻可以請求.

查找一番后,問題出現(xiàn)在了兩個main thread死鎖的地方.也就是信號量和AFHTTPSessionManager的默認complate queue.這個時候,手動設(shè)置complate queue即可:

manager.completionQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

返回值依然是一個字典,key為url.

當(dāng)然會出現(xiàn)url相同的情況,這個時候key如何處理可以多斟酌一番,加上index?

more

需求的功能當(dāng)然還可以有更多,例如巧哥提供了緩存,返回值驗證,斷點續(xù)傳等
有必要的話完全可以繼續(xù)擴展

Action(Model)

網(wǎng)絡(luò)庫的核心思路是把每一個請求封裝成對象.所以每一個請求對應(yīng)一個Action

請求有3種,action當(dāng)然也就有3個.

  • ZCApiAction
  • ZCApiUploadAction
  • ZCApiDownloadAction

后2種繼承自第一種.action中主要包含api的請求相關(guān)信息,例如url,params等.也包含一些api的控制信息,例如log開關(guān).最后提供了2個回調(diào),實現(xiàn)"插件機制":

typedef void (^ZCActionComplation) (BOOL isSuccess);
typedef void (^ZCVoidBlock) (void);

@property (nonatomic, copy)   ZCVoidBlock        actionWillInvokeBlock;
@property (nonatomic, copy)   ZCActionComplation actionDidInvokeBlock;

通過這兩個回調(diào),可以在一個請求之前,顯示相應(yīng)的hud,請求完畢后顯示成功或者失敗,然后去除.

在upload action中,需要支持單文件和多文件上傳兩種方式.所以提供了2組值(data/name/filename/mime):單個的形式(NSData和NSString)以及數(shù)組的形式.

使用

沒有提供pod~~~可以把源文件拷貝,然后import "ZCApiLauncher.h"即可.

只是希望討論一個恰當(dāng)?shù)姆绞?實際上每個團隊都會自己維護一套適合自己的網(wǎng)絡(luò)庫.合適自己項目約定的才是最好的.

才疏學(xué)淺,有不對的地方請指正.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末瘫想,一起剝皮案震驚了整個濱河市骤素,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌磁滚,老刑警劉巖拣挪,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件擦酌,死亡現(xiàn)場離奇詭異,居然都是意外死亡菠劝,警方通過查閱死者的電腦和手機赊舶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赶诊,“玉大人笼平,你說我怎么就攤上這事√蚧荆” “怎么了寓调?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長锄码。 經(jīng)常有香客問我夺英,道長,這世上最難降的妖魔是什么滋捶? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任痛悯,我火速辦了婚禮,結(jié)果婚禮上重窟,老公的妹妹穿的比我還像新娘载萌。我一直安慰自己,他們只是感情好巡扇,可當(dāng)我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布扭仁。 她就那樣靜靜地躺著,像睡著了一般厅翔。 火紅的嫁衣襯著肌膚如雪乖坠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天知给,我揣著相機與錄音瓤帚,去河邊找鬼描姚。 笑死,一個胖子當(dāng)著我的面吹牛戈次,可吹牛的內(nèi)容都是我干的轩勘。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼怯邪,長吁一口氣:“原來是場噩夢啊……” “哼绊寻!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起悬秉,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤澄步,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后和泌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體村缸,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年武氓,在試婚紗的時候發(fā)現(xiàn)自己被綠了梯皿。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡县恕,死狀恐怖东羹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情忠烛,我是刑警寧澤属提,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站美尸,受9級特大地震影響冤议,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜师坎,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一求类、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧屹耐,春花似錦、人聲如沸椿猎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽犯眠。三九已至按灶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間筐咧,已是汗流浹背鸯旁。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工噪矛, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人铺罢。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓艇挨,卻偏偏與公主長得像,于是被迫代替她去往敵國和親韭赘。 傳聞我的和親對象是個殘疾皇子缩滨,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,700評論 2 354

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)泉瞻,斷路器脉漏,智...
    卡卡羅2017閱讀 134,654評論 18 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,808評論 6 342
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件袖牙、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,098評論 4 62
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法侧巨,類相關(guān)的語法,內(nèi)部類的語法鞭达,繼承相關(guān)的語法司忱,異常的語法,線程的語...
    子非魚_t_閱讀 31,625評論 18 399
  • ¥開啟¥ 【iAPP實現(xiàn)進入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個線程碉怔,因...
    小菜c閱讀 6,404評論 0 17