讀AFNetworking代碼(一)

代碼輪廓

今天開(kāi)始準(zhǔn)備把最新AFNetworking的代碼通讀一下胁艰,做一下筆記的記錄漾岳。打開(kāi)代碼腋寨,我們從接口文件開(kāi)始切入蹋砚,順路看一下代碼的目錄結(jié)構(gòu)是怎么樣的扼菠。AFNetworking中對(duì)外的文件是AFNetworking.h摄杂。

//! Project version number for AFNetworking.
FOUNDATION_EXPORT double AFNetworkingVersionNumber;
//! Project version string for AFNetworking.
FOUNDATION_EXPORT const unsigned char AFNetworkingVersionString[];

代碼開(kāi)始向外界暴露了兩個(gè)變量這兩個(gè)變量告訴外界自己的版本信息,便于用于分析版本對(duì)于自己的代碼的影響循榆。正常邏輯中可能用不太上析恢,但是一旦發(fā)生一些跟版本相關(guān)的復(fù)雜又比較難查找的問(wèn)題,那么用戶可能發(fā)現(xiàn)版本信息的用途還是很大的秧饮。

接下來(lái)的代碼AFNetworking.hAFNetworking中用戶可能用到的頭文件依次暴露了出去映挂,大家可以根據(jù)自己的需求依次查閱,這里不再贅余盗尸。我們直接打開(kāi)文件目錄看一下代碼的結(jié)構(gòu)柑船。

現(xiàn)在的代碼中有兩個(gè)核心的目錄,AFNetworkingUIKit+AFNetworking泼各。AFNetworking包含與通信相關(guān)的核心代碼鞍时,UIKit+AFNetworking中是一些跟UI相關(guān)的應(yīng)用代碼,即這個(gè)目錄中基本上是對(duì)AFNetworking代碼的一些封裝扣蜻,給用戶一些方便的接口來(lái)使用AFNetworking目錄中的通信代碼逆巍。我們代碼的閱讀從AFNetworking這個(gè)目錄開(kāi)始。

AFCompatibilityMacros.h
AFHTTPSessionManager.h
AFHTTPSessionManager.m
AFNetworkReachabilityManager.h
AFNetworkReachabilityManager.m
AFSecurityPolicy.h
AFSecurityPolicy.m
AFURLRequestSerialization.h
AFURLRequestSerialization.m
AFURLResponseSerialization.h
AFURLResponseSerialization.m
AFURLSessionManager.h
AFURLSessionManager.m

從目錄上看莽使,我們可以將其分為這幾個(gè)功能模塊:

  • 網(wǎng)絡(luò)監(jiān)聽(tīng)模塊(AFNetworkReachabilityManager)
  • 網(wǎng)絡(luò)安全策略模塊(AFSecurityPolicy)
  • 網(wǎng)絡(luò)通信信息序列化/反序列化模塊(AFURLRequestSerialization/AFURLResponseSerialization)
  • 網(wǎng)絡(luò)通信模塊(AFURLSessionManager锐极、AFHTTPSessionManager)

AFNetworking是基于NSURLSession來(lái)做的,它的核心類是AFURLSessionManager,而AFHTTPSessionManager繼承于AFURLSessionManager吮旅,它封裝了一些Http的方法和邏輯處理溪烤,其實(shí)歸根結(jié)底會(huì)把真正的請(qǐng)求交給AFURLSessionManager來(lái)做。而AFURLSessionManager則是將于NSURLSession做了一系列的封裝庇勃,最終將請(qǐng)求交給NSURLSession檬嘀,然后從NSURLSession的代理回調(diào)中拿到數(shù)據(jù)傳遞給上層。下面是AFNetworking的一個(gè)簡(jiǎn)單的架構(gòu)框圖责嚷,等到后面我們?cè)囍嫵?code>AFNetworking的類圖鸳兽,會(huì)更復(fù)雜一點(diǎn),目前從最頂層來(lái)看架構(gòu)圖就是下圖所示的情況:

AFNetworking架構(gòu)圖.png

從一個(gè)請(qǐng)求看過(guò)去
    AFHTTPSessionManager *client = [[AFHTTPSessionManager alloc] init];
    [client GET:@"http://localhost" parameters:nil headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        
    }];

我們通過(guò)AFHTTPSessionManager初始化了一個(gè)client的實(shí)例罕拂,緊接著調(diào)用一個(gè)方法發(fā)送了一個(gè)請(qǐng)求揍异,調(diào)用這個(gè)方法的時(shí)候,我們發(fā)送了自己的需要請(qǐng)求數(shù)據(jù)的接口地址爆班,然后可以填寫一些參數(shù)衷掷,請(qǐng)求的結(jié)果通過(guò)successfailure的回調(diào)傳遞回來(lái)。我們就從這次網(wǎng)絡(luò)請(qǐng)求看過(guò)去柿菩,從初始化到發(fā)送請(qǐng)求的參數(shù)整合序列化戚嗅,到最后收到數(shù)據(jù)已經(jīng)數(shù)據(jù)序列化之后返回給回調(diào)中,來(lái)分析代碼的流程是怎樣的。
首先是這個(gè)初始化方法懦胞,我們打開(kāi)代碼點(diǎn)進(jìn)去看:

- (instancetype)init {
    return [self initWithBaseURL:nil];
}

- (instancetype)initWithBaseURL:(NSURL *)url {
    return [self initWithBaseURL:url sessionConfiguration:nil];
}

- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
    return [self initWithBaseURL:nil sessionConfiguration:configuration];
}
- (instancetype)initWithBaseURL:(NSURL *)url
           sessionConfiguration:(NSURLSessionConfiguration *)configuration
{
    self = [super initWithSessionConfiguration:configuration];
    if (!self) {
        return nil;
    }

    // 若果url path的長(zhǎng)度大于0且url不是以斜杠結(jié)尾的,那么給url的末尾添加斜杠
    if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) {
        url = [url URLByAppendingPathComponent:@""];
    }

    self.baseURL = url;

    self.requestSerializer = [AFHTTPRequestSerializer serializer];
    self.responseSerializer = [AFJSONResponseSerializer serializer];

    return self;
}
  • 初始化方法最終都調(diào)用了- (instancetype)initWithBaseURL:(NSURL *)url sessionConfiguration:(NSURLSessionConfiguration *)configuration這個(gè)方法替久,而這個(gè)方法調(diào)用了父類的方法- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration
  • 將url賦值給self.baseURL
  • self.requestSerialerself.responseSerializer賦值。
    self.baseURL后面的代碼會(huì)遇到躏尉,序列化和反序列化的類我們也放在后面再看蚯根。我們直接來(lái)到父類中看一下[super initWithSessionConfiguration:configuration];的方法。
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
    self = [super init];
    if (!self) {
        return nil;
    }

    if (!configuration) {
        configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    }

    self.sessionConfiguration = configuration;

    self.operationQueue = [[NSOperationQueue alloc] init];
    //并發(fā)隊(duì)列的最大線程數(shù)設(shè)為1
    self.operationQueue.maxConcurrentOperationCount = 1;

    self.responseSerializer = [AFJSONResponseSerializer serializer];

    self.securityPolicy = [AFSecurityPolicy defaultPolicy];

#if !TARGET_OS_WATCH
    self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
#endif

    self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];

    self.lock = [[NSLock alloc] init];
    self.lock.name = AFURLSessionManagerLockName;

    __weak typeof(self) weakSelf = self;
    [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
        
        __strong typeof(weakSelf) strongSelf = weakSelf;
        for (NSURLSessionDataTask *task in dataTasks) {
            [strongSelf addDelegateForDataTask:task uploadProgress:nil downloadProgress:nil completionHandler:nil];
        }

        for (NSURLSessionUploadTask *uploadTask in uploadTasks) {
            [strongSelf addDelegateForUploadTask:uploadTask progress:nil completionHandler:nil];
        }

        for (NSURLSessionDownloadTask *downloadTask in downloadTasks) {
            [strongSelf addDelegateForDownloadTask:downloadTask progress:nil destination:nil completionHandler:nil];
        }
    }];

    return self;
}
  • 初始化了一些屬性
  • 初始化了一個(gè)操作隊(duì)列胀糜,最大并發(fā)數(shù)設(shè)置為1
    這個(gè)比較讓人疑惑颅拦,為啥將并發(fā)隊(duì)列最大并發(fā)數(shù)設(shè)置為1了,那么我們就看一下這個(gè)隊(duì)列里面都做了什么僚纷,應(yīng)該就能找到其中的原委了矩距。
- (NSURLSession *)session {
    
    @synchronized (self) {
        if (!_session) {
            _session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];
        }
    }
    return _session;
}

即這個(gè)操作隊(duì)列是處理NSURLSession代理返回的,那么我們?cè)倏纯创矸祷乩锩孀隽耸裁础?/p>

AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask];
- (AFURLSessionManagerTaskDelegate *)delegateForTask:(NSURLSessionTask *)task {
    NSParameterAssert(task);

    AFURLSessionManagerTaskDelegate *delegate = nil;
    [self.lock lock];
    delegate = self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)];
    [self.lock unlock];

    return delegate;
}

首先都是通過(guò)一個(gè)task找到一個(gè)AFURLSessionManagerTaskDelegate類型的對(duì)象怖竭,這個(gè)delegate對(duì)象存在mutableTaskDelegatesKeyedByTaskIdentifier這個(gè)字典里面锥债,為了保證這個(gè)字典的多線程安全,對(duì)他的訪問(wèn)都加了一把鎖痊臭,所以即便是代碼回調(diào)的操作隊(duì)列最大并發(fā)數(shù)不設(shè)置為1哮肚,因?yàn)殒i的存在,下一個(gè)請(qǐng)求還是得等待一直到上個(gè)請(qǐng)求獲取完所要的資源后解鎖广匙,所以這邊并發(fā)回調(diào)是沒(méi)有意義的允趟。相反如果多任務(wù)的去回調(diào)處理,由于鎖的存在反而會(huì)增加性能的消耗鸦致。

  • 緊接著調(diào)用了下面這個(gè)方法
 __weak typeof(self) weakSelf = self;
    [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
       
    }];

獲取task然后對(duì)task的一些屬性做了置空的操作潮剪,(這有個(gè)毛用?分唾?抗碰?)內(nèi)心的潛臺(tái)詞是不是這樣的,在一個(gè)初始化方法里绽乔,會(huì)拿到task嗎弧蝇?好吧,我只能相信大神折砸,然后去網(wǎng)上找一下答案了看疗。為什么在initWithSessionConfiguration中執(zhí)行self.session getTasksWithCompletionHandler? #3499 AFNetworking的issue中有這個(gè)答案睦授,希望對(duì)大家有幫助两芳。是為了后臺(tái)返回的時(shí)候可能重新初始化,然后后臺(tái)有一些任務(wù)未完成去枷,導(dǎo)致崩潰盗扇。

初始化方法小結(jié)

寫到這里初始化的方法就讀完了祷肯,我們簡(jiǎn)單回顧一下沉填,其實(shí)主要的目的就是生成一個(gè)NSURLSession,圍繞這它我們做了sessionConfiguration疗隶,回調(diào)代理隊(duì)列的初始化,反序列化responseSerializer的初始化翼闹,安全策略方針securityPolicy的初始化斑鼻,網(wǎng)絡(luò)監(jiān)聽(tīng)器reachabilityManager的初始化,容器mutableTaskDelegatesKeyedByTaskIdentifier的初始化猎荠。其實(shí)都是為了發(fā)送請(qǐng)求和接收回調(diào)提前做好準(zhǔn)備坚弱。

好吧,下一篇吧关摇,估計(jì)再啰嗦下去就受不了了荒叶。下一篇我們接著看請(qǐng)求是如何生成的,如何發(fā)送的输虱。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末些楣,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子宪睹,更是在濱河造成了極大的恐慌愁茁,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件亭病,死亡現(xiàn)場(chǎng)離奇詭異鹅很,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)罪帖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門促煮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人整袁,你說(shuō)我怎么就攤上這事菠齿。” “怎么了葬项?”我有些...
    開(kāi)封第一講書人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵泞当,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我民珍,道長(zhǎng)襟士,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任嚷量,我火速辦了婚禮陋桂,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蝶溶。我一直安慰自己嗜历,他們只是感情好宣渗,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著梨州,像睡著了一般痕囱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,301評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音扳抽,去河邊找鬼枯芬。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼蟆炊,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了瀑志?” 一聲冷哼從身側(cè)響起涩搓,我...
    開(kāi)封第一講書人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎后室,沒(méi)想到半個(gè)月后缩膝,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡岸霹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年疾层,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贡避。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡痛黎,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出刮吧,到底是詐尸還是另有隱情湖饱,我是刑警寧澤,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布杀捻,位于F島的核電站井厌,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏致讥。R本人自食惡果不足惜仅仆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望垢袱。 院中可真熱鬧墓拜,春花似錦、人聲如沸请契。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至涌韩,卻和暖如春畔柔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背贸辈。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工释树, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人擎淤。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像秸仙,于是被迫代替她去往敵國(guó)和親嘴拢。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354

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

  • 我還是喜歡你寂纪,像云漂泊大半生席吴,不曾歇息。 我還是喜歡你捞蛋,像太陽(yáng)升了落去孝冒,無(wú)論朝夕。 我還是喜歡你拟杉,像風(fēng)走了八萬(wàn)里庄涡,...
    c98b1091bf47閱讀 164評(píng)論 0 0
  • 1拿穴、“老大泣洞,明年可以給我漲薪吧?” 這個(gè)問(wèn)題默色,是我剛進(jìn)入一家公司的時(shí)候球凰,跟同事們一起去吃飯的路上,一位外地辦事處的...
    修心匠的私享會(huì)閱讀 756評(píng)論 0 6
  • 董一菲說(shuō):“一個(gè)人心中有難排解的苦痛時(shí)腿宰,喜歡去藏地尋找出路”呕诉。這些天也逐漸認(rèn)同一個(gè)說(shuō)法:寫作可以疏通內(nèi)心的...
    流水脈脈閱讀 274評(píng)論 0 3
  • 黑方左手膀手防住對(duì)方中路進(jìn)攻(下圖) 黑方左手拿住對(duì)手左手,右手同時(shí)進(jìn)攻對(duì)手紅方腹部酗失,紅方右手自然防守自己腹部义钉,用...
    Justin劉勇慧閱讀 341評(píng)論 1 1