代碼輪廓
今天開(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.h
將AFNetworking
中用戶可能用到的頭文件依次暴露了出去映挂,大家可以根據(jù)自己的需求依次查閱,這里不再贅余盗尸。我們直接打開(kāi)文件目錄看一下代碼的結(jié)構(gòu)柑船。
現(xiàn)在的代碼中有兩個(gè)核心的目錄,AFNetworking
和UIKit+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)圖就是下圖所示的情況:
從一個(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ò)success和failure的回調(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.requestSerialer
和self.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)備坚弱。