這篇文章不光是我對(duì)自己知識(shí)的一個(gè)總結(jié)颤陶,更多的是想通過這篇文章認(rèn)識(shí)到自己的不足恨溜。希望大家能給點(diǎn)建議疾捍。大家相互學(xué)習(xí)!
網(wǎng)絡(luò)層在一個(gè)App中也是一個(gè)不可缺少的部分峻呛,好的網(wǎng)絡(luò)層不光能提升開發(fā)效率還要能提升用戶體驗(yàn)罗售。另外,蘋果對(duì)網(wǎng)絡(luò)請求部分已經(jīng)做了很好的封裝钩述,業(yè)界的AFNetworking也被廣泛使用寨躁。
在網(wǎng)絡(luò)層搭建過程中碰到的難點(diǎn)和問題這里先提出來。
主要會(huì)講這些方面:
1.使用哪種交互模式來跟業(yè)務(wù)層做對(duì)接牙勘?
2.使用集約化調(diào)用方式還是離散型調(diào)用方式去調(diào)用API职恳?
3.是否有必要將API返回的數(shù)據(jù)封裝成對(duì)象然后再交付給業(yè)務(wù)層?
1.使用哪種交互模式來跟業(yè)務(wù)層做對(duì)接方面?
我這里是以Delegate為主 Notification為輔來跟業(yè)務(wù)層做對(duì)接的放钦。
初期公司是以block作為主要交互模式。遇到的結(jié)果如下:
1.1.block很難追蹤恭金,難以維護(hù)
在調(diào)試的時(shí)候經(jīng)常會(huì)單步追蹤到某一個(gè)地方之后操禀,發(fā)現(xiàn)尼瑪這里有個(gè)block,如果想知道這個(gè)block里面都做了些什么事情横腿,這時(shí)候就比較蛋疼了颓屑。
1.2.回調(diào)方法不統(tǒng)一斤寂,不便于調(diào)試和維護(hù)
在同一個(gè)Controller里 因?yàn)槭褂胋lock發(fā)起請求,響應(yīng)的著陸點(diǎn)不一樣調(diào)試和維護(hù)起來不方便揪惦。在跟業(yè)務(wù)層對(duì)接的部分只采用一種對(duì)接手段(在我這兒就是只采用delegate這一個(gè)手段)限制靈活性遍搞,以此來交換應(yīng)用的可維護(hù)性
1.3.block會(huì)延長相關(guān)對(duì)象的生命周期
在網(wǎng)絡(luò)回調(diào)中使用block,是block導(dǎo)致對(duì)象生命周期被延長的其中一個(gè)場合器腋,當(dāng)ViewController從window中卸下時(shí)溪猿,如果尚有請求帶著block在外面飛,然后block里面引用了ViewController(這種場合非常常見)纫塌,那么ViewController是不能被及時(shí)回收的再愈,即便你已經(jīng)取消了請求,那也還是必須得等到請求著陸之后才能被回收护戳。然而使用delegate就不會(huì)有這樣的問題,delegate是弱引用垂睬,哪怕請求仍然在外面飛媳荒,,ViewController還是能夠及時(shí)被回收的驹饺,回收之后指針自動(dòng)被置為了nil钳枕,無傷大雅。
為了解決這些問題和統(tǒng)一回調(diào)方法赏壹,便于調(diào)試和維護(hù)鱼炒。所以我們選擇了delegate為主要設(shè)計(jì)模式。至于為什么沒有選Notification為主要設(shè)計(jì)模式蝌借?是因?yàn)镹otification的影響面不可控制昔瞧,只要存在實(shí)例就存在被影響的可能。這也會(huì)導(dǎo)致誰都不能保證相關(guān)處理代碼就在唯一的那個(gè)地方菩佑,進(jìn)而帶來維護(hù)災(zāi)難自晰。 但是在某些層面上(比如:網(wǎng)絡(luò)切換)需要多個(gè)APIManage處理一些問題。所以選擇Notification為輔助設(shè)計(jì)模式稍坯。
2.使用集約化調(diào)用方式還是離散型調(diào)用方式去調(diào)用API酬荞?
集約型API調(diào)用其實(shí)就是所有API的調(diào)用只有一個(gè)類,然后這個(gè)類接收API名字瞧哟,API參數(shù)混巧,以及回調(diào)著陸點(diǎn)(可以是target-action,或者block勤揩,或者delegate等各種模式的著陸點(diǎn))作為參數(shù)咧党。然后執(zhí)行類似startRequest這樣的方法,它就會(huì)去根據(jù)這些參數(shù)起飛去調(diào)用API了陨亡,然后獲得API數(shù)據(jù)之后再根據(jù)指定的著陸點(diǎn)去著陸凿傅。
集約型API調(diào)用方式:[APIRequeststartRequestWithApiName:@"itemList.v1"params:paramssuccess:@selector(success:)fail:@selector(fail:)target:self];
離散型API調(diào)用是這樣的缠犀,一個(gè)API對(duì)應(yīng)于一個(gè)APIManager,然后這個(gè)APIManager只需要提供參數(shù)就能起飛聪舒,API名字辨液、著陸方式都已經(jīng)集成入APIManager中。
離散型API調(diào)用方式:@property(nonatomic,strong)ItemListAPIManager*itemListAPIManager;// getter-(ItemListAPIManager*)itemListAPIManager{if(_itemListAPIManager==nil){_itemListAPIManager=[[ItemListAPIManageralloc]init];_itemListAPIManager.delegate=self;}return_itemListAPIManager;}// 使用的時(shí)候就這么寫:[self.itemListAPIManagerloadDataWithParams:params];
這里我更傾向于離散型API調(diào)用方式箱残。原因如下:
原因1:當(dāng)前請求正在外面飛著的時(shí)候滔迈,根據(jù)不同的業(yè)務(wù)需求存在兩種不同的請求起飛策略:一個(gè)是取消新發(fā)起的請求,等待外面飛著的請求著陸被辑。另一個(gè)是取消外面飛著的請求燎悍,讓新發(fā)起的請求起飛。集約化的API調(diào)用方式如果要滿足這樣的需求盼理,那么每次要調(diào)用的時(shí)候都要多寫一部分判斷和取消的代碼谈山,手段就做不到很干凈。
前者的業(yè)務(wù)場景舉個(gè)例子就是刷新頁面的請求宏怔,刷新詳情奏路,刷新列表等。后者的業(yè)務(wù)場景舉個(gè)例子是列表多維度篩選臊诊,比如你先篩選了商品類型鸽粉,然后篩選了價(jià)格區(qū)間。當(dāng)然抓艳,后者的情況不一定每次篩選都要調(diào)用API触机,我們先假設(shè)這種篩選每次都必須要通過調(diào)用API才能獲得數(shù)據(jù)。
如果是離散型的API調(diào)用玷或,在編寫不同的APIManager時(shí)候就可以針對(duì)不同的API設(shè)置不同的起飛策略儡首,在實(shí)際使用的時(shí)候,就可以不必關(guān)心起飛策略了偏友,因?yàn)锳PIMananger里面已經(jīng)寫好了椒舵。
原因2:當(dāng)API請求的著陸點(diǎn)消失時(shí),離散型的API調(diào)用方式能夠更加透明地處理這種情況约谈。
當(dāng)一個(gè)頁面的請求正在天上飛的時(shí)候笔宿,用戶等了好久不耐煩了,小手點(diǎn)了個(gè)back棱诱,然后ViewController被pop被回收泼橘。此時(shí)請求的著陸點(diǎn)就沒了。這是很危險(xiǎn)的情況迈勋,著陸點(diǎn)要是沒了炬灭,就很容易crash的。一般來說處理這個(gè)情況都是在dealloc的時(shí)候取消當(dāng)前頁面所有的請求靡菇。如果是集約型的API調(diào)用重归,這個(gè)代碼就要寫到ViewController的dealloc里面米愿,但如果是離散型的API調(diào)用,這個(gè)代碼寫到APIManager里面就可以了鼻吮,然后隨著ViewController的回收進(jìn)程育苟,APIManager也會(huì)被跟著回收,這部分代碼就得到了調(diào)用的機(jī)會(huì)椎木。這樣業(yè)務(wù)方在使用的時(shí)候就可以不必關(guān)心著陸點(diǎn)消失的情況了违柏,從而更加關(guān)注業(yè)務(wù)。
綜上: 上部分使用離散型設(shè)計(jì)(發(fā)起請求部分)香椎,下部分使用集約型設(shè)計(jì)(回調(diào)部分)漱竖。
3.是否有必要將API返回的數(shù)據(jù)封裝成對(duì)象然后再交付給業(yè)務(wù)層?
對(duì)于網(wǎng)絡(luò)層而言畜伐,統(tǒng)一的請求回調(diào)方式和參數(shù)有利于提升應(yīng)用的可維護(hù)性馍惹。對(duì)api返回?cái)?shù)據(jù)封裝成對(duì)象或者采用NSDictionary加Const字符串key來表征都是可行的。
這里我更傾向使用對(duì)象封裝返回?cái)?shù)據(jù)玛界。
原因:在使用過程中通過對(duì)象返回的數(shù)據(jù)使用起來更加便利万矾。沒必要去找NSDictionary key有哪些。只需要點(diǎn)擊對(duì)象模型就能清晰了解對(duì)象結(jié)構(gòu)并以點(diǎn)的獲取屬性就可以加以使用脚仔。
總結(jié):
關(guān)于網(wǎng)絡(luò)層搭建基本都是圍繞著幾個(gè)問題來的。問題解決完了舆绎,一個(gè)簡潔版的網(wǎng)絡(luò)層也就出來了鲤脏。為了使開發(fā)人員能不看文檔也能使用你的框架,暴露出去的接口盡量做到簡潔易懂吕朵。