AFNetworking是iOS開(kāi)發(fā)中基本都會(huì)用到的一個(gè)網(wǎng)絡(luò)框架琐脏;閱讀其源碼對(duì)理解iOS的網(wǎng)絡(luò)開(kāi)發(fā)很有幫助量蕊。
概述
在3.0版本中叮称,AFNetworking也放棄了使用NSURLConnection
漠畜,全面轉(zhuǎn)向NSURLSession
,其框架結(jié)構(gòu)基本如下:
框架結(jié)構(gòu)圖
通常我們直接使用的是
AFHTTPSessionManager
類锭沟,因?yàn)樵趇OS開(kāi)發(fā)中基本都是采用http(https)
類型的網(wǎng)絡(luò)通信協(xié)議笼痹。
AFURLRequestSerialization模塊分析
AFURLRequestSerialization
主要作用是生成一個(gè)封裝好各種參數(shù)的NSMutableURLRequest
配喳。其文件內(nèi)部的結(jié)構(gòu)如下:
AFURLRequestSerialization結(jié)構(gòu)圖
創(chuàng)建網(wǎng)絡(luò)請(qǐng)求時(shí),我們根據(jù)不同需要凳干,選擇
AFHTTPRequestSerializer
晴裹、AFJSONRequestSerializer
、AFPropertyRequestSerializer
三種Serializer之一來(lái)創(chuàng)建Request救赐。
// 基本邏輯如下:
if (method == get || head || delete) {
// 將parameters拼接成URL字符串加到URL后
} else if (multipart表單提交) {
// 通過(guò)圖中的AFStreamingMultipartFormData來(lái)將參數(shù)及相應(yīng)數(shù)據(jù)變成一項(xiàng)項(xiàng)的AFHTTPBodyPart中涧团,然后給HTTPBodyStream賦值
} else { // put || post || patch
/**
1.HTTPSerializer: 將參數(shù)編碼拼接成字符串轉(zhuǎn)成NSData
2.JSONSerializer: 將參數(shù)以dataWithJSONObject方式轉(zhuǎn)成NSData
3.PropertyListSerializer:將參數(shù)以dataWithPropertyList方式轉(zhuǎn)成NSData
然后將NSData放到HTTPBody中
*/
}
/* HTTPBody和HTTPBodyStream是互斥的 */
// 附multipart格式
let boundary = wfWiEWrgEFA9A78512weF7106A
--boundary //開(kāi)始
Content-Disposition: form-data; name="status"
abcddsdf
--boundary
Content-Disposition: form-data; name="source"
2582981980
--boundary
Content-Disposition: form-data; name="access_token"
2.00nVexdfsfsoBgbvnoCcdfs4esfac4c4Nksmwc
--boundary
Content-Disposition: form-data; name="pic"; filename="test.png";Content-Type=image/png
...這里是文件的二進(jìn)制數(shù)據(jù)...
--boundary-- //結(jié)束
AFURLResponseSerialization模塊分析
Response的序列化相對(duì)比較簡(jiǎn)單,結(jié)構(gòu)圖如下:
image.png
代碼簡(jiǎn)析
- (BOOL)validateResponse:(NSHTTPURLResponse *)response
data:(NSData *)data
error:(NSError * __autoreleasing *)error
{
BOOL responseIsValid = YES;
NSError *validationError = nil;
// 判斷是HTTPURLResponse類型
if (response && [response isKindOfClass:[NSHTTPURLResponse class]]) {
// 如果response中的MIMEType不是可接受的類型
if (self.acceptableContentTypes &&
![self.acceptableContentTypes containsObject:[response MIMEType]] &&
!([response MIMEType] == nil && [data length] == 0)) {
if ([data length] > 0 && [response URL]) {
NSMutableDictionary *mutableUserInfo = [@{
NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: unacceptable content-type: %@", @"AFNetworking", nil), [response MIMEType]],
NSURLErrorFailingURLErrorKey:[response URL],
AFNetworkingOperationFailingURLResponseErrorKey: response,
} mutableCopy];
if (data) {
mutableUserInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] = data;
}
validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:mutableUserInfo], validationError);
}
responseIsValid = NO;
}
// 如果status !(200-299)经磅,同樣創(chuàng)建錯(cuò)誤信息
if (self.acceptableStatusCodes && ![self.acceptableStatusCodes containsIndex:(NSUInteger)response.statusCode] && [response URL]) {
NSMutableDictionary *mutableUserInfo = [@{
NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: %@ (%ld)", @"AFNetworking", nil), [NSHTTPURLResponse localizedStringForStatusCode:response.statusCode], (long)response.statusCode],
NSURLErrorFailingURLErrorKey:[response URL],
AFNetworkingOperationFailingURLResponseErrorKey: response,
} mutableCopy];
if (data) {
mutableUserInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] = data;
}
validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorBadServerResponse userInfo:mutableUserInfo], validationError);
responseIsValid = NO;
}
}
if (error && !responseIsValid) {
*error = validationError;
}
return responseIsValid;
}
AFSecurityPolicy模塊分析
有三種驗(yàn)證模式
typedef NS_ENUM(NSUInteger, AFSSLPinningMode) {
AFSSLPinningModeNone, // 會(huì)在系統(tǒng)信任的證書列表里驗(yàn)證服務(wù)器的證書是否可信
AFSSLPinningModePublicKey, // 需要客戶端保存有服務(wù)器端的證書拷貝泌绣,驗(yàn)證客戶端保存的與要驗(yàn)證的服務(wù)器的是否一致
AFSSLPinningModeCertificate,// 需要客戶端保存有服務(wù)器端的證書拷貝,但是只驗(yàn)證公鑰是否一致
};
默認(rèn)采用的是AFSSLPinningModeNone预厌。
AFNetworkReachabilityManager模塊分析
網(wǎng)絡(luò)狀態(tài)
typedef NS_ENUM(NSInteger, AFNetworkReachabilityStatus) {
AFNetworkReachabilityStatusUnknown = -1,
AFNetworkReachabilityStatusNotReachable = 0,
AFNetworkReachabilityStatusReachableViaWWAN = 1,
AFNetworkReachabilityStatusReachableViaWiFi = 2,
};
AFURLSessionManager/AFHTTPSessionManager模塊分析
同樣阿迈,結(jié)構(gòu)圖如下:
結(jié)構(gòu)圖
每個(gè)
NSURLSessionTask
對(duì)應(yīng)著一個(gè)AFURLSessionManagerTaskDelegate
,在AFURLSessionManager
以鍵值對(duì)的方式存儲(chǔ)在manager
中
- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
forTask:(NSURLSessionTask *)task
{
NSParameterAssert(task);
NSParameterAssert(delegate);
[self.lock lock];
// 用taskIdentifier(每個(gè)session創(chuàng)建的task的identifier是唯一的)作為key值轧叽,存儲(chǔ)delegate
self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
[self addNotificationObserverForTask:task];
[self.lock unlock];
}
- (AFURLSessionManagerTaskDelegate *)delegateForTask:(NSURLSessionTask *)task {
NSParameterAssert(task);
AFURLSessionManagerTaskDelegate *delegate = nil;
[self.lock lock];
delegate = self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)];
[self.lock unlock];
return delegate;
}
即每個(gè)task上的處理交由AFURLSessionManagerTaskDelegate
處理苗沧。
其它
_AFURLSessionTaskSwizzling
中采用method swizzling
,交換了系統(tǒng)NSURLSessionTask
的suspend
和resume
方法炭晒,分別在兩個(gè)方法原有的基礎(chǔ)上添加了通知待逞。
參考:
chenxianming的博客