多閱讀別人的源碼是一種學(xué)習(xí),尤其是牛掰人的源碼,可惜自己是個渣渣進(jìn)不了BAT這種大廠俯画,所以只能靠閱讀優(yōu)秀的第三方框架來增長自己的知識面了蜕径,就算是這樣也是才開始两踏,不過亡羊補(bǔ)牢未為晚矣,啥時候醒悟都不晚兜喻,所以堅(jiān)持堅(jiān)持梦染,
如題所示,首先看上的就是AFNetWorking的源碼朴皆,重要性不多說了帕识,我覺得iOS程序員百分百都用過了,沒用過估計(jì)不是大牛遂铡,就是異類啦肮疗,封裝的沒的說,我這水平也難一下子窺其全貌扒接,在上班時間偷偷的看了幾天才總算了解各大概伪货,寫下了不求有多少人會看到们衙,但求把自己的理解寫下來避免忘記,水平再差也算一點(diǎn)心得嘛碱呼。
不多說先上圖拉出來溜溜:
先說個大概蒙挑,然后每個類分別展開,最后在分析一下運(yùn)行過程愚臀,我覺得能掌握到這步就差不多啦忆蚀,剩下再多的,就看你的內(nèi)功如何了懊悯。
AFHTTPSessionManager
為啥說AFN牛逼呢蜓谋,就是因?yàn)樗o用戶提供的接口很簡單,只要傳入簡單的參數(shù)就可以在block中拿到數(shù)據(jù)炭分,非常方便桃焕,然后這種方便不代表實(shí)現(xiàn)起來方便(有點(diǎn)跑題)。AFHTTPSessionManager就是暴露給用戶的最外層封裝捧毛,給用戶很簡單的函數(shù)接口观堂,來實(shí)現(xiàn)很cool的功能。
平時使用率95%的get 和 post 接口一目了然呀忧。前面幾函數(shù)都是初始化函數(shù)师痕,最后接種到此函數(shù)對,URLSession 進(jìn)行簡單的配置而账。
AFHTTPSessionManager類繼承自AFURLSessionManager類胰坟,所以在此類可以看到很多super方法,這些都是配置URLSession的泞辐,這個下面在展開笔横。
經(jīng)過初始化后當(dāng)用戶想要調(diào)用網(wǎng)絡(luò)請求時,只要一個函數(shù)即可
其實(shí)所有的網(wǎng)絡(luò)請求都是調(diào)用中間的一個函數(shù)咐吼,封裝出來這么多函數(shù)就只能怪oc固有的坑了吹缔,
AFURLSessionManager
此類為AFN的核心類,封裝了URLSession 歷史不多說啦锯茄,如果有不明白的親們可以Google 一下URLSession厢塘,蘋果爸爸全面推薦,已經(jīng)把老的廢除了肌幽,同時還推薦一本入門好書晚碾,讀了它腰不酸,腿不疼了牍颈,一口氣擼一天也不需要營養(yǎng)快線了迄薄。
接著言歸正傳,正式初始化AFURLSessionManager的時候煮岁,干了幾件事
最開始初始化了一個默認(rèn)的配置[NSURLSessionConfiguration defaultSessionConfiguration] 讥蔽,這貨簡單就是可以配置http請求的涣易,這跟URLSession的設(shè)計(jì)有關(guān),每個請求都可以獨(dú)立配置冶伞。
然后創(chuàng)建了一個最大運(yùn)行數(shù)為1的隊(duì)列新症,說白了就是同步的啊,這樣我覺得可以避免資源競爭响禽,而且可以節(jié)省資源徒爹,(注:AFN2的時候此處是創(chuàng)建一條常駐線程,其實(shí)效果是一樣的芋类,如果每次請求的時候都開線程隆嗅,請求后再關(guān)閉,這期間就會浪費(fèi)好多資源啊侯繁,所以單開一個常駐線程宾肺,這樣所有的請求來的時候都走這一個線程雾狈,省資源祖娘,這也算一個曝光率比較高的面試題掷倔,寫到這想到了所以說一下)。
然后初始化了一個NSURLSession進(jìn)行網(wǎng)絡(luò)通信用咕别。然后初始化一個解析返回報文體的實(shí)例技健,默認(rèn)初始化的是json解析的(大部分網(wǎng)絡(luò)都是這個套路)。
然后初始化一個AFSecurityPolicy類惰拱,這個類是負(fù)責(zé)https加密雌贱,以及協(xié)商秘鑰xxx等操作的,后學(xué)再講偿短,因?yàn)檫@個類是單獨(dú)的帽芽,不知道它并不影響其他的學(xué)習(xí)。
然后開始又初始化了網(wǎng)絡(luò)監(jiān)控AFNetworkReachabilityManager翔冀,這貨也是可以單獨(dú)使用的,功能說白了很簡單披泪,就是通過橋接bridge 來監(jiān)控當(dāng)前的網(wǎng)絡(luò)狀態(tài):無網(wǎng)纤子、未知網(wǎng)絡(luò)、WiFi款票、手機(jī)網(wǎng)絡(luò)等控硼。
然后初始化一個字典,會把該session下的所有Task通過ID存到字典里艾少,并且初始化一個NSLock卡乾,這把鎖基本上就是鎖住這個字典的,因?yàn)锳FN整體上來說是異步的缚够,避免數(shù)據(jù)混亂造成資源競爭幔妨。
一個session里面可能存在三種Task: 數(shù)據(jù)傳輸鹦赎、下載、上傳误堡。便利session 把緩存的session 都存到字典里古话。并且為task設(shè)置delegate。
此函數(shù)先進(jìn)行了初始化了代理AFURLSessionManagerTaskDelegate锁施,主要的是初始化了一個NSProgress實(shí)例(我之前也沒用過陪踩,是封裝的管理進(jìn)度的類,主要是用于管理下載悉抵,和上傳進(jìn)度的)肩狂,
然后把Task的代理用字典保存起來,在此處加鎖姥饰,為了防止資源混亂原因不說啦傻谁,然后設(shè)置通知,讓外界可以觀察到這一變化媳否。
三種代理設(shè)置代理的方式基本上相同栅螟,只不過在添加下載代理中添加了如果有下載的資源為其單獨(dú)添加下載資源的回調(diào)。
再往后不得不說創(chuàng)建Task任務(wù)了
再此處創(chuàng)建了一個全局的串行隊(duì)列篱竭,保證發(fā)出請求不會錯亂(本人所在公司是帶藍(lán)牙硬件的力图,前人遺留的‘財富’中根本沒有這東西,導(dǎo)致經(jīng)常會出現(xiàn)很詭異的數(shù)據(jù)問題掺逼,滿滿的都是坑啊),還有個人認(rèn)為這種用static的這種方式不錯吃媒,可以多用呢
同樣如之前的代碼,創(chuàng)建Task也分三種吕喘,每種都有一點(diǎn)不一樣
創(chuàng)建uploadTask中添加了對最大上傳數(shù)的判斷赘那,AFMaximumNumberOfAttemptsToRecreateBackgroundSessionUploadTask最大默認(rèn)上傳數(shù)為3 而且根據(jù)上傳的是文件還是data還有不同的封裝,
剩下封裝了一堆NSURLSessionDataDelegate 和NSURLSessionDownloadDelegate 基本了氯质,基本上都是通過回調(diào)的方式搞的募舟,讓用戶能比較方便的使用AFN闻察,這玩意可以參看這蘋果官方api慢慢看,功能一目了然辕漂。
剩下還有AFURLSessionManagerTaskDelegate在前面也介紹了,他的初始化钉嘹,簡單的來說URLSession 就是通過NSURLSessionConfiguration實(shí)現(xiàn)對網(wǎng)絡(luò)條件的配置鸯乃,通過NSURLSession創(chuàng)建加載http請求的信息跋涣,通過Task來實(shí)現(xiàn)動作鸟悴。這是我個人的理解不一定對哈,但是最少簡單明了宏蛉,感覺又說跑了哈遣臼。
這個類中最關(guān)鍵的就是接收到數(shù)據(jù)傳輸解析數(shù)據(jù)的方法啦
實(shí)現(xiàn)了**- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask )task didCompleteWithError:(NSError )error;代理,官方解釋
告訴代理任務(wù)完成傳輸數(shù)據(jù)揍堰。
服務(wù)器錯誤不會通過錯誤參數(shù)報告嗅义。代表通過錯誤參數(shù)收到的唯一錯誤是客戶端錯誤,例如無法解析主機(jī)名或連接到主機(jī)之碗。
說白了就是http請求完成后的回調(diào)。代碼創(chuàng)建了一個字典存了一下有關(guān)網(wǎng)絡(luò)請求的信息幽纷,包括返回的值等self.mutableData 是在接收返回數(shù)據(jù)的代理中被賦值的博敬,如果有錯誤信息則把錯誤拋回去(例如:code=1022,iOS9后不支持http請求等,xxx信息)偏窝。如果沒有錯誤信息即認(rèn)為是正確的。
這一句把返回的數(shù)據(jù)穿進(jìn)去伦意,其實(shí)就是兜一圈根據(jù)你的初始化解析報文體什么格式的數(shù)據(jù)就按照什么格式的解析硼补,最后傳回來。最后把返回的數(shù)據(jù)通過回調(diào)趕回去已骇,這就是一個接收過程就完事啦疾捍。拼的字典最后通過通知傳出去了栏妖,給需要的類,或者自己接收也行啊吊趾。如果不嫌麻煩的話??瑟啃。
在下面就是對于下載數(shù)據(jù)的一些代理封裝揩尸,怎么拼數(shù)據(jù)啥的,不多敘述
_AFURLSessionTaskSwizzling
這個類用到了runtime的高級api 替換函數(shù)错负,主要是替換Task 中的resume勇边、suspend方法犹撒,加上通知,當(dāng)此函數(shù)執(zhí)行后可以發(fā)出通知告知業(yè)務(wù)類粒褒。借鑒網(wǎng)上的說法识颊,這是一個神奇的類奕坟,為啥說神奇月杉,不多說直接上代碼 在load方法時就開始搞事情了。
到此AFURLSessionManager這個類就說的差不多奠伪,我這也只能窺其部分首懈。不能窺其全貌啊,不過這個類算AFN的核心類了究履,其他的類都是為他服務(wù)的最仑,一定要多看幾遍。
AFURLResponseSerialization
這個類意在根據(jù)不同的返回體解析數(shù)據(jù)泥彤。所有的子類都需要實(shí)現(xiàn)AFURLResponseSerialization代理方法,這個代理有且只有一個這個方法菱父。
在AFHTTPResponseSerializer類中init方法很簡單 就是初始化了一個NSIndexSet浙宜。acceptableContentTypes參數(shù)為所每種響應(yīng)格式所以解析的返回頭中的信息
然后就是一個公共的驗(yàn)證響應(yīng)有效性的方法啦
剩下的類目都是事先代理方法,根據(jù)不同數(shù)據(jù)格式進(jìn)行解析同仆,沒啥好解釋的啦裙品,大家自己看啦。
AFHTTPRequestSerializer
這個類是拼裝請求頭清酥,和請求體焰轻,具體的http協(xié)議的知識,如果不清楚的請看我推薦的書辱志,我后面會發(fā)個鏈接供大家下載。
初始化的時候默認(rèn)使用UTF-8 拼接出來的信息都存在了mutableHTTPRequestHeaders字典中什乙。其中HTTPMethodsEncodingParametersInURI初始化了通用拼裝的請求類型 已球,大家知道post是所以的信息是不會頻道URL里的而是放到請求體里的智亮。然后初始化了幾個URLSession的參數(shù).
allowsCellularAccess 會根據(jù)電量和電源燈情況自動設(shè)置最佳值
cachePolicy 設(shè)置緩存策略 NSURLRequestUseProtocolCachePolicy 對特定的 URL 請求使用網(wǎng)絡(luò)協(xié)議中實(shí)現(xiàn)的緩存邏輯。這是默認(rèn)的策略 使用默認(rèn)的緩存策略,用kvo監(jiān)聽這幾個值的變化阔蛉,從而知道用戶的需求,這種方法我覺得是不想暴露最核心的URLSession聋呢。
HTTPShouldHandleCookies 設(shè)置cookies
HTTPShouldUsePipelining 保證每個URLSession 都會開啟一個單獨(dú)的連接池
networkServiceType
timeoutInterval
在每次發(fā)起網(wǎng)絡(luò)請求時都會調(diào)用此方法輕裝請求頭颠区,這也算核心方法
中間的for循環(huán)是根據(jù)kvo獲取到的值用kvc 的方式加載到NSMutableURLRequest中毕莱,設(shè)置屬性测暗,最后需要把保存到字典里的方法格式化橙http請求所用到的格式
首先把已有格式轉(zhuǎn)換成字典 如果parameters附帶信息不為空磨澡,使用NSString * AFQueryStringFromParameters(NSDictionary *parameters)字典轉(zhuǎn)出URL編碼形式质和,URL編碼就是一堆%的那種格式,不知道自己Google吧最后做個判斷如果不是post形式的就把參數(shù)拼接到URL的后面 如果為post的就拼接到請求體中厦酬。
剩下的是拼裝body 我也不是特別明白了瘫想,一般的情況下不需要,等我了解后把這部分補(bǔ)上减噪,只能說我也學(xué)習(xí)不夠啊车吹,還在不斷的看書中,
AFNetworkReachabilityManager
AFSecurityPolicy
這兩個類我也不是特別懂了朝卒,都是用底層C語言去封裝的乐埠,要是硬著頭皮來需要看好久,我推薦大家看看大牛的講解就好了瑞眼,對于我這種渣渣來說實(shí)在是有心無力啊扯罐,不過還好這兩個類都是單獨(dú)的,不了解的話也不影響你對AFN核心業(yè)務(wù)的理解歹河。
總結(jié):其實(shí)看完AFN我還是感觸頗多秸歧,之前對http不是很了解,逼著自己去看源碼還是很起作用的键菱,感覺受益良多,AFN除了主業(yè)務(wù)以外還有一些分類補(bǔ)充UIKit UIKit+AFNetworking 這個我會后續(xù)再寫一篇拭抬,自私的說不為別人,為自己也得寫一篇傅蹂,我覺得把東西寫出來后可以很好的補(bǔ)充一下當(dāng)時被忽略的東西算凿,很有用。