AFNetworking 是 Objective-C 中用于網(wǎng)絡(luò)請(qǐng)求的第三方框架,我們一般使用它來(lái)封裝網(wǎng)絡(luò)請(qǐng)求,這篇文章記錄了閱讀 AFNetworking(Version 3.1.0) 源碼的筆記榜聂,簡(jiǎn)單的研究了它的實(shí)現(xiàn)細(xì)節(jié)闹司。
AFHTTPSessionManager
AFHTTPSessionManager 繼承自 AFURLSessionManager嗤朴,主要是提供了一系列對(duì)外暴露的屬性和方法配椭,如下圖:
可以看出對(duì)外暴露的有:
三個(gè)屬性:baseURL
、requestSerializer
雹姊、responseSerializer
三個(gè)初始化方法:
+ (instancetype)manager
- (instancetype)initWithBaseURL:(nullable NSURL *)url
- (instancetype)initWithBaseURL:(nullable NSURL *)url
sessionConfiguration:(nullable NSURLSessionConfiguration *)configuration
還有一系列請(qǐng)求方法:GET
股缸、HEAD
、POST
吱雏、PUT
敦姻、PATCH
、DELETE
歧杏。
初始化與請(qǐng)求方法
其中所有的初始化方法镰惦,最后都到initWithBaseURL:
方法里來(lái)初始化對(duì)象,需要注意的是默認(rèn) response 是 JSON 類型的犬绒。
- (instancetype)initWithBaseURL:(NSURL *)url
sessionConfiguration:(NSURLSessionConfiguration *)configuration
{
...
self.baseURL = url;
// 默認(rèn)的 request 和 response
self.requestSerializer = [AFHTTPRequestSerializer serializer];
self.responseSerializer = [AFJSONResponseSerializer serializer];
return self;
}
而所有的請(qǐng)求方法旺入,GET
、HEAD
凯力、POST
茵瘾、PUT
、PATCH
沮协、DELETE
等最終都是調(diào)用的 dataTaskWithHTTPMethod:
方法創(chuàng)建 task龄捡,區(qū)別是傳遞的method名稱不同卓嫂,方法體如下:
NSError *serializationError = nil;
// 創(chuàng)建 NSMutableURLRequest
NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
...處理構(gòu)建 request 產(chǎn)生的錯(cuò)誤
// 創(chuàng)建 dataTask
__block NSURLSessionDataTask *dataTask = nil;
dataTask = [self dataTaskWithRequest:request
uploadProgress:uploadProgress
downloadProgress:downloadProgress
completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
...
}];
return dataTask;
其中先創(chuàng)建 request慷暂,再根據(jù) request 創(chuàng)建 dataTask。
NSSecureCoding
@interface AFHTTPSessionManager : AFURLSessionManager <NSSecureCoding, NSCopying>
可以看出 AFHTTPSessionManager 實(shí)現(xiàn)了 NSSecureCoding 和 NSCoding 協(xié)議晨雳,其中 NSSecureCoding 是基于 NSCoding 協(xié)議行瑞。
NSSecureCoding 是蘋果在 iOS6 中引入的一個(gè)新協(xié)議,基于NSCoding餐禁。簡(jiǎn)單的說(shuō)就是在數(shù)據(jù)歸檔過(guò)程加了數(shù)據(jù)類型檢驗(yàn)血久,相對(duì)更安全一點(diǎn),使用起來(lái)需要多實(shí)現(xiàn)一個(gè)方法:
@protocol NSSecureCoding <NSCoding>
@required
+ (BOOL)supportsSecureCoding;
@end
小結(jié)
總的來(lái)說(shuō) AFHTTPSessionManager 只是在 AFURLSessionManager 的基礎(chǔ)上做了一層包裝帮非。
AFURLSessionManager
AFURLSessionManager 可以說(shuō)是 AFNetworking 的核心類氧吐,相應(yīng)的其內(nèi)部實(shí)現(xiàn)也復(fù)雜許多,先來(lái)看一張圖:
AFURLSessionManager.m 內(nèi)部除了 AFURLSessionManager 的實(shí)現(xiàn)外末盔,還包含兩個(gè)自定義類的實(shí)現(xiàn)筑舅,AFURLSessionManagerTaskDelegate 主要為 task 提供進(jìn)度管理功能,_AFURLSessionTaskSwizzling 則是修改 NSURLSessionTask 的 resume
和 suspend
方法陨舱,這里還是先從 AFURLSessionManager 初始化開始翠拣。
初始化
AFURLSessionManager 的初始化在initWithSessionConfiguration:
方法里進(jìn)行了一系列的配置:
// 默認(rèn)為 defaultSessionConfiguration
if (!configuration) {
configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
}
self.sessionConfiguration = configuration;
// 初始化代理隊(duì)列
self.operationQueue = [[NSOperationQueue alloc] init];
self.operationQueue.maxConcurrentOperationCount = 1;
// 初始化 session
self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];
// 初始化 response 序列,默認(rèn)為 JSON
self.responseSerializer = [AFJSONResponseSerializer serializer];
// AFSecurityPolicy 是 AFNetworking 用來(lái)保證 HTTP 請(qǐng)求安全的類游盲,它被 AFURLSessionManager 持有
self.securityPolicy = [AFSecurityPolicy defaultPolicy];
#if !TARGET_OS_WATCH
self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
#endif
// 初始化用來(lái)存放 AFURLSessionManagerTaskDelegate 的字典
self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];
// 初始化 NSLock
self.lock = [[NSLock alloc] init];
self.lock.name = AFURLSessionManagerLockName;
...為已有的 task 設(shè)置代理
創(chuàng)建 NSURLSessionTask
創(chuàng)建 NSURLSessionTask 的方法有以下三種:
dataTaskWithRequest:
uploadTaskWithRequest:
downloadTaskWithRequest:
這里以 dataTaskWithRequest:
方法為例误墓,可以看出其是用 NSURLSession 的 dataTaskWithRequest:
方法創(chuàng)建出 dataTask蛮粮。
__block NSURLSessionDataTask *dataTask = nil;
// 解決iOS8之前的一個(gè)bug
url_session_manager_create_task_safely(^{
// 用NSURLSession創(chuàng)建NSURLSessionDataTask
dataTask = [self.session dataTaskWithRequest:request];
});
// 給data task添加了一個(gè)AFURLSessionManagerTaskDelegate
// 主要為 task 提供進(jìn)度管理功能
[self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];
return dataTask;
需要注意的是在創(chuàng)建完 dataTask 之后,又通過(guò) addDelegateForDataTask:
方法給 dataTask 添加了一個(gè) AFURLSessionManagerTaskDelegate谜慌,這個(gè) delegate 主要為 dataTask 提供上傳下載的進(jìn)度管理功能然想。
NSURLSession 相關(guān)的代理方法
@interface AFURLSessionManager : NSObject <NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate, NSSecureCoding, NSCopying>
AFURLSessionManager 遵循并實(shí)現(xiàn)了一系列 NSURLSession 相關(guān)的代理方法,不過(guò) AFURLSessionManager 為所有的代理協(xié)議都提供了對(duì)應(yīng)的 block 接口欣范,這樣不讓用戶自己實(shí)現(xiàn)相關(guān)方法又沾,對(duì)外只暴露出 block。這里舉個(gè)??:
- (void)URLSession:(NSURLSession *)session
didBecomeInvalidWithError:(NSError *)error
{
if (self.sessionDidBecomeInvalid) {
self.sessionDidBecomeInvalid(session, error);
}
[[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDidInvalidateNotification object:session];
}
可以看出在以上方法中熙卡,用戶只需要調(diào)用這個(gè) block杖刷, 就可以用來(lái)處理session無(wú)效的情況,這么做隱藏了細(xì)節(jié)驳癌,簡(jiǎn)化了調(diào)用滑燃。
AFURLSessionManagerTaskDelegate
AFURLSessionManagerTaskDelegate 繼承自 NSObject,主要作用是為 dataTask 提供進(jìn)度管理功能颓鲜。
需要注意的是在 AFURLSessionManagerTaskDelegate 的 setupProgressForTask
方法中將 NSProgress 和 NSURLSessionTask 進(jìn)行了狀態(tài)綁定表窘,代碼如下:
/*
上傳的totalUnitCount就對(duì)應(yīng)期望發(fā)送(send)的數(shù)據(jù)大小,下載任務(wù)的就對(duì)應(yīng)期望接收(receive)的數(shù)據(jù)大小甜滨。
接著就是設(shè)置這兩個(gè)NSProgress對(duì)應(yīng)的cancel乐严、pause和resume這三個(gè)狀態(tài),正好對(duì)應(yīng)session task的cancel衣摩、suspend和resume三個(gè)狀態(tài)
*/
self.uploadProgress.totalUnitCount = task.countOfBytesExpectedToSend;
self.downloadProgress.totalUnitCount = task.countOfBytesExpectedToReceive;
[self.uploadProgress setCancellable:YES];
[self.uploadProgress setCancellationHandler:^{
__typeof__(weakTask) strongTask = weakTask;
[strongTask cancel];
}];
[self.uploadProgress setPausable:YES];
[self.uploadProgress setPausingHandler:^{
__typeof__(weakTask) strongTask = weakTask;
[strongTask suspend];
}];
if ([self.uploadProgress respondsToSelector:@selector(setResumingHandler:)]) {
[self.uploadProgress setResumingHandler:^{
__typeof__(weakTask) strongTask = weakTask;
[strongTask resume];
}];
}
[self.downloadProgress setCancellable:YES];
[self.downloadProgress setCancellationHandler:^{
__typeof__(weakTask) strongTask = weakTask;
[strongTask cancel];
}];
[self.downloadProgress setPausable:YES];
[self.downloadProgress setPausingHandler:^{
__typeof__(weakTask) strongTask = weakTask;
[strongTask suspend];
}];
if ([self.downloadProgress respondsToSelector:@selector(setResumingHandler:)]) {
[self.downloadProgress setResumingHandler:^{
__typeof__(weakTask) strongTask = weakTask;
[strongTask resume];
}];
}
// 給兩個(gè)progress添加KVO NSProgress的fractionCompleted屬性(任務(wù)已經(jīng)完成的比例昂验,取值為0~1)
[self.downloadProgress addObserver:self
forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
options:NSKeyValueObservingOptionNew
context:NULL];
[self.uploadProgress addObserver:self
forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
options:NSKeyValueObservingOptionNew
context:NULL];
_AFURLSessionTaskSwizzling
_AFURLSessionTaskSwizzling
的唯一功能就是修改 NSURLSessionTask 的 resume
和 suspend
方法,使用 af_resume
艾扮、af_suspend
替換原有的實(shí)現(xiàn)既琴,主要實(shí)現(xiàn)是在 +load
方法中實(shí)現(xiàn)了 method swizzling。
總結(jié)
本文只列舉了一些主要的知識(shí)點(diǎn)泡嘴,詳細(xì)的可以看源碼注釋甫恩。