AFNetworking源碼閱讀

AFNetworking是我們常用的網(wǎng)絡(luò)庫(kù)狈醉,我們有必要對(duì)其有必要的了解瞻鹏,以便進(jìn)行二次封裝和遇到問(wèn)題時(shí)能及時(shí)的進(jìn)行調(diào)試开仰。而AF本身是對(duì)系統(tǒng)的NSURLSession進(jìn)行的封裝脐往,所以想了解AF的整體架構(gòu),有必要先了解一下OC對(duì)于網(wǎng)絡(luò)請(qǐng)求的基本姿勢(shì)谒获。

一個(gè)簡(jiǎn)單的網(wǎng)絡(luò)請(qǐng)求

    NSURL *url = [NSURL URLWithString:@"http://www.apple.com"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
    NSURLSession *holdSession = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
    
    NSURLSessionDataTask * dataTask =  [holdSession dataTaskWithRequest:request completionHandler:^(NSData * __nullable data, NSURLResponse * __nullable response, NSError * __nullable error) {
        NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;
        NSLog(@"******%@\n%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding],res.allHeaderFields);
        if (error) {
            NSLog(@"******error:%@",[error localizedDescription]);
        }
    }];
    
    [dataTask resume];

構(gòu)建一個(gè)網(wǎng)絡(luò)請(qǐng)求:

第一步:先準(zhǔn)備一個(gè)URL組建成NSRequest

第二步:根據(jù)配置信息NSURLSessionConfiguration構(gòu)建一個(gè)會(huì)話NSURLSession

第三步:給NSURLSession分配一個(gè)數(shù)據(jù)請(qǐng)求的任務(wù)dataTaskWithRequest

第四步:異步發(fā)送請(qǐng)求蛤肌,處理回調(diào)的數(shù)據(jù)。

看來(lái)我們用系統(tǒng)API發(fā)送一個(gè)網(wǎng)絡(luò)請(qǐng)求還是很方便的芭裸准!但是構(gòu)建一個(gè)穩(wěn)定高效的網(wǎng)絡(luò)系統(tǒng),我們還是有很多坑要填的赔硫,我們就來(lái)看下AFNetworking吧炒俱。

AFNetworking的基本架構(gòu)

AFNetworking.png

右側(cè)為非核心模塊:

Security模塊:為安全模塊,處理https鏈接中的SSL相關(guān)配置卦停。

UIKit模塊:為一些系統(tǒng)類的拓展和輔助功能向胡,像圖片的緩存恼蓬,相關(guān)網(wǎng)絡(luò)控件網(wǎng)絡(luò)事件的監(jiān)控惊完。

Reachability是AF自己封裝的監(jiān)測(cè)網(wǎng)絡(luò)狀態(tài)的模塊。

左側(cè)為網(wǎng)絡(luò)請(qǐng)相關(guān)核心模塊

AFHTTPRequestSerializer本事是一個(gè)協(xié)議处硬,就一個(gè)方法小槐。這個(gè)方法傳入兩個(gè)參數(shù):NSURLRequest和URL參數(shù)字典,返回一個(gè)NSURLRequest荷辕。目的是實(shí)現(xiàn)對(duì)應(yīng)前面栗子中NSURLRequest進(jìn)行封裝凿跳,主要是對(duì)于請(qǐng)求頭和各種請(qǐng)求形態(tài)的編碼預(yù)處理,達(dá)到http請(qǐng)求的要求疮方。下面是對(duì)其包含的相關(guān)類進(jìn)行一下說(shuō)明控嗜。

主要有三種請(qǐng)求格式:
大部分的請(qǐng)求都是AFHTTPRequestSerializer這個(gè)來(lái)完成的也是默認(rèn)的配置,另外還有AFJSONRequestSerializer和AFPropertyListRequestSerializer兩種請(qǐng)求類型骡显,這兩者都是繼承與AFHTTPRequestSerializer疆栏,主要在于前者用于特別的處理請(qǐng)求content-type是json文件的時(shí)候曾掂,后者用于特別的處理請(qǐng)求content-type是plist文件的時(shí)候。

AFQueryStringPair實(shí)現(xiàn)對(duì)網(wǎng)絡(luò)請(qǐng)求數(shù)據(jù)進(jìn)行編碼并組建成鍵值對(duì)用=連接,編碼相關(guān)問(wèn)題可以來(lái)這里看壁顶。主要是內(nèi)聯(lián)函數(shù)AFPercentEscapedStringFromString實(shí)現(xiàn)了相關(guān)設(shè)置珠洗。

AFStreamingMultipartFormData主要用于文件上傳時(shí)的一些設(shè)置。它其中有一個(gè)主要屬性就是AFMultipartBodyStream若专,其繼承于NSInputStream许蓖,是對(duì)讀取上傳資源文件流的一些設(shè)置。

AFHTTPBodyPart主要是post或put請(qǐng)求中的請(qǐng)求體相關(guān)的設(shè)置

AFURLResponseSerialization類本身也是一個(gè)協(xié)議调衰,該方法傳入一個(gè)response和一個(gè)data返回指定類型的對(duì)象膊爪。這個(gè)協(xié)議用于出來(lái)網(wǎng)絡(luò)請(qǐng)求返回的數(shù)據(jù)response,對(duì)數(shù)據(jù)進(jìn)行驗(yàn)證嚎莉、解碼蚁飒,并根據(jù)MIME類型返回正確的數(shù)據(jù)。

AFHTTPResponseSerializer下面其他幾個(gè)類型的基類萝喘,用于驗(yàn)證返回的數(shù)據(jù)是否正確淮逻,確認(rèn)解碼方式,code碼等阁簸。

AFJSONResponseSerializer處理application/json爬早、text/json、text/javascript數(shù)據(jù)启妹,我們最常用的出具處理方式筛严,返回序列化后的id對(duì)象。

AFXMLParserResponseSerializer和AFXMLDocumentResponseSerializer處理application/xml饶米、text/xml數(shù)據(jù)桨啃。前者生成NSXMLParser對(duì)象,后者生成NSXMLDocument對(duì)象檬输。

AFPropertyListResponseSerializer處理application/x-plist數(shù)據(jù)

AFImageResponseSerializer處理image這個(gè)主類型下所有類型

AFCompoundResponseSerializer應(yīng)對(duì)多種處理類型照瘾,自行判斷可以處理的類型。

AFHTTPSessionManager繼承與AFURLSessionManager丧慈,針對(duì)HTTP請(qǐng)求的各種請(qǐng)求類型進(jìn)行了封裝析命,主要目的是對(duì)外提供便于使用的接口,這里實(shí)現(xiàn)了栗子中逃默,NSURLRequest的準(zhǔn)備鹃愤,拿到對(duì)應(yīng)的task,并對(duì)task進(jìn)行啟動(dòng)完域。

AFURLSessionManager核心類软吐,實(shí)現(xiàn)對(duì)task請(qǐng)求的hook,準(zhǔn)備session吟税,監(jiān)控session的各種代理狀態(tài)凹耙,監(jiān)控task的各種代理狀態(tài)鸟蟹,并利用AFURLResponseSerialization進(jìn)行數(shù)據(jù)的解析與回調(diào)。

NSURLSessionConfiguration是比較重要的配置信息類使兔,三個(gè)初始化方法:

  • +defaultSessionConfiguration返回標(biāo)準(zhǔn)配置建钥,共享NSHTTPCookieStorage,共享NSURLCache和共享NSURLCredentialStorage虐沥;
  • +ephemeralSessionConfiguration返回一個(gè)預(yù)設(shè)配置熊经,沒(méi)有持久性存儲(chǔ)的緩存,Cookie或證書欲险;+
  • +backgroundSessionConfiguration:它會(huì)創(chuàng)建一個(gè)后臺(tái)session镐依,它以在應(yīng)用程序掛起,退出天试,甚至崩潰的情況下運(yùn)行上傳和下載任務(wù)槐壳。

_AFURLSessionTaskSwizzling實(shí)現(xiàn)對(duì)resume、suspend的hook喜每,并發(fā)送通知务唐。

AFURLSessionManagerTaskDelegate實(shí)現(xiàn)對(duì)task的上傳、下載進(jìn)度的回調(diào)带兜,獲取數(shù)據(jù)枫笛,獲取到完整數(shù)據(jù)后進(jìn)行回調(diào)。

AFNetworking的線程相關(guān)問(wèn)題

網(wǎng)絡(luò)的重點(diǎn)在于數(shù)據(jù)的高并發(fā)處理刚照,所以有必要研究一下AF在線程方面所做的努力刑巧。

 self.operationQueue = [[NSOperationQueue alloc] init];
 self.operationQueue.maxConcurrentOperationCount = 1;
 self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];

AF創(chuàng)建session的時(shí)候會(huì)建一個(gè)隊(duì)列傳進(jìn)去,這個(gè)隊(duì)列默認(rèn)設(shè)置最大并發(fā)數(shù)只有1,第一次這個(gè)session啟動(dòng)一個(gè)任務(wù)的時(shí)候啟動(dòng)一個(gè)線程來(lái)處理這個(gè)網(wǎng)絡(luò)請(qǐng)求任務(wù)无畔,以后這個(gè)會(huì)話下的任務(wù)默認(rèn)都是在這個(gè)線程中順序執(zhí)行得啊楚。

- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
            forTask:(NSURLSessionTask *)task
{
    NSParameterAssert(task);
    NSParameterAssert(delegate);

    [self.lock lock];
    self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
    [delegate setupProgressForTask:task];
    [self addNotificationObserverForTask:task];
    [self.lock unlock];
}

session每次啟動(dòng)一個(gè)任務(wù),就會(huì)創(chuàng)建一個(gè)AFURLSessionManagerTaskDelegate的delegate對(duì)象浑彰,用于處理數(shù)據(jù)恭理。AFHTTPSessionManager有一個(gè)字典屬性mutableTaskDelegatesKeyedByTaskIdentifier用于存放以taskID為鍵,delegate對(duì)象為值得一組數(shù)據(jù)闸昨,這個(gè)delegate對(duì)象就是AFURLSessionManagerTaskDelegate生成的對(duì)象蚯斯。此處為應(yīng)對(duì)可能在不同的線程生成任務(wù),添加了鎖饵较,防止線程競(jìng)爭(zhēng)造成的數(shù)據(jù)異常。

 dispatch_async(url_session_manager_processing_queue(), ^{
            NSError *serializationError = nil;
            responseObject = [manager.responseSerializer responseObjectForResponse:task.response data:data error:&serializationError];

            .......
            
            dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{
                if (self.completionHandler) {
                    self.completionHandler(task.response, responseObject, serializationError);
                }

                dispatch_async(dispatch_get_main_queue(), ^{
                    [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
                });
            });
        });

此處代碼是數(shù)據(jù)回來(lái)之后遭赂,對(duì)數(shù)據(jù)的處理循诉。由于要處理的數(shù)據(jù)可能很大,所以首先開啟一個(gè)異步并發(fā)隊(duì)列url_session_manager_processing_queue撇他,在子線程中處理數(shù)據(jù)茄猫,處理完成后再回調(diào)到應(yīng)該去的線程狈蚤。通過(guò)異步group,判斷是否用戶創(chuàng)建了group划纽,如果沒(méi)有就創(chuàng)建一個(gè)脆侮,同時(shí)判斷用戶是否創(chuàng)建了完成的隊(duì)列completionQueue,如果沒(méi)有就返回到主線程勇劣。理我可以監(jiān)聽自定義group靖避,可以實(shí)現(xiàn)多個(gè)請(qǐng)求完畢后的統(tǒng)一處;通過(guò)設(shè)置自定義completionQueue比默,可以讓我們的數(shù)據(jù)返回到自定義線程幻捏,一個(gè)場(chǎng)景就是返回的數(shù)據(jù)可能要進(jìn)行大量的計(jì)算,這個(gè)時(shí)候我們沒(méi)必要返回主線程命咐,直接去自定義的子線程做這些復(fù)雜計(jì)算篡九,待完成后再回到主線程去刷新UI。最后還有一個(gè)點(diǎn)就是為了保證通知在主線程醋奠,特地做了異步返回主線程去發(fā)通知榛臼。

總結(jié):

AFNetworking面向接口編程,整體架構(gòu)清爽窜司,每個(gè)點(diǎn)拓展開來(lái)都有不少內(nèi)容讽坏,值得我們學(xué)習(xí),我只是對(duì)架構(gòu)進(jìn)行了整體的分析例证,希望對(duì)大家有所啟發(fā)路呜。閑來(lái)無(wú)事大家可以就感興趣的一些模塊仔細(xì)閱讀,定會(huì)對(duì)整個(gè)網(wǎng)絡(luò)請(qǐng)求以及線程的管理有更多的理解织咧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末胀葱,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子笙蒙,更是在濱河造成了極大的恐慌抵屿,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件捅位,死亡現(xiàn)場(chǎng)離奇詭異轧葛,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)艇搀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門尿扯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人焰雕,你說(shuō)我怎么就攤上這事衷笋。” “怎么了矩屁?”我有些...
    開封第一講書人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵辟宗,是天一觀的道長(zhǎng)爵赵。 經(jīng)常有香客問(wèn)我,道長(zhǎng)泊脐,這世上最難降的妖魔是什么空幻? 我笑而不...
    開封第一講書人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮容客,結(jié)果婚禮上秕铛,老公的妹妹穿的比我還像新娘。我一直安慰自己耘柱,他們只是感情好如捅,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著调煎,像睡著了一般镜遣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上士袄,一...
    開封第一講書人閱讀 51,573評(píng)論 1 305
  • 那天悲关,我揣著相機(jī)與錄音,去河邊找鬼娄柳。 笑死寓辱,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的赤拒。 我是一名探鬼主播秫筏,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼挎挖!你這毒婦竟也來(lái)了这敬?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蕉朵,失蹤者是張志新(化名)和其女友劉穎崔涂,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體始衅,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡冷蚂,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了汛闸。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蝙茶。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蛉拙,靈堂內(nèi)的尸體忽然破棺而出尸闸,到底是詐尸還是另有隱情,我是刑警寧澤孕锄,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布吮廉,位于F島的核電站,受9級(jí)特大地震影響畸肆,放射性物質(zhì)發(fā)生泄漏宦芦。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一轴脐、第九天 我趴在偏房一處隱蔽的房頂上張望调卑。 院中可真熱鬧,春花似錦大咱、人聲如沸恬涧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)溯捆。三九已至,卻和暖如春厦瓢,著一層夾襖步出監(jiān)牢的瞬間提揍,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工煮仇, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留劳跃,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓浙垫,卻偏偏與公主長(zhǎng)得像刨仑,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子夹姥,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

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

  • 前言 在AFNetworking源碼閱讀1中杉武,我們已經(jīng)閱讀完了AFHTTPSessionManager類。本篇我們...
    Wang66閱讀 1,096評(píng)論 0 8
  • 前言 在上篇AFNetworking源碼閱讀2——核心快結(jié)尾時(shí)佃声,解釋了為什么在AFURLSessionManage...
    Wang66閱讀 800評(píng)論 0 5
  • 從三月份找實(shí)習(xí)到現(xiàn)在艺智,面了一些公司,掛了不少圾亏,但最終還是拿到小米十拣、百度、阿里志鹃、京東夭问、新浪、CVTE曹铃、樂(lè)視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,248評(píng)論 11 349
  • 有時(shí)候想想以前父母教育或者說(shuō)對(duì)待自己的一些事缰趋,心里還是會(huì)覺(jué)得難受。有時(shí)候很想把那些話和想法告訴他們,可又覺(jué)得何必呢...
    黎容閱讀 187評(píng)論 0 0
  • 懷著對(duì)摩梭人的母系大家庭的神秘秘血,我們一家人包車來(lái)到了瀘沽湖畔味抖,湖水清澈見底,近岸的湖面上漂浮著小白花灰粮,當(dāng)?shù)厝私凶鏊?..
    佰荷閱讀 4,944評(píng)論 0 1