AFNetworking是iOS开发中基本都会用到的一个网络框架;阅读其源码对理解iOS的网络开发很有帮助。
概述
在3.0版本中,AFNetworking也放弃了使用NSURLConnection
,全面转向NSURLSession
,其框架结构基本如下:
通常我们直接使用的是
AFHTTPSessionManager
类,因为在iOS开发中基本都是采用http(https)
类型的网络通信协议。
AFURLRequestSerialization模块分析
AFURLRequestSerialization
主要作用是生成一个封装好各种参数的NSMutableURLRequest
。其文件内部的结构如下:
创建网络请求时,我们根据不同需要,选择
AFHTTPRequestSerializer
、AFJSONRequestSerializer
、AFPropertyRequestSerializer
三种Serializer之一来创建Request。
// 基本逻辑如下:
if (method == get || head || delete) {
// 将parameters拼接成URL字符串加到URL后
} else if (multipart表单提交) {
// 通过图中的AFStreamingMultipartFormData来将参数及相应数据变成一项项的AFHTTPBodyPart中,然后给HTTPBodyStream赋值
} else { // put || post || patch
/**
1.HTTPSerializer: 将参数编码拼接成字符串转成NSData
2.JSONSerializer: 将参数以dataWithJSONObject方式转成NSData
3.PropertyListSerializer:将参数以dataWithPropertyList方式转成NSData
然后将NSData放到HTTPBody中
*/
}
/* HTTPBody和HTTPBodyStream是互斥的 */
// 附multipart格式
let boundary = wfWiEWrgEFA9A78512weF7106A
--boundary //开始
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
...这里是文件的二进制数据...
--boundary-- //结束
AFURLResponseSerialization模块分析
Response的序列化相对比较简单,结构图如下:
代码简析
- (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),同样创建错误信息
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模块分析
有三种验证模式
typedef NS_ENUM(NSUInteger, AFSSLPinningMode) {
AFSSLPinningModeNone, // 会在系统信任的证书列表里验证服务器的证书是否可信
AFSSLPinningModePublicKey, // 需要客户端保存有服务器端的证书拷贝,验证客户端保存的与要验证的服务器的是否一致
AFSSLPinningModeCertificate,// 需要客户端保存有服务器端的证书拷贝,但是只验证公钥是否一致
};
默认采用的是AFSSLPinningModeNone。
AFNetworkReachabilityManager模块分析
网络状态
typedef NS_ENUM(NSInteger, AFNetworkReachabilityStatus) {
AFNetworkReachabilityStatusUnknown = -1,
AFNetworkReachabilityStatusNotReachable = 0,
AFNetworkReachabilityStatusReachableViaWWAN = 1,
AFNetworkReachabilityStatusReachableViaWiFi = 2,
};
AFURLSessionManager/AFHTTPSessionManager模块分析
同样,结构图如下:
每个
NSURLSessionTask
对应着一个AFURLSessionManagerTaskDelegate
,在AFURLSessionManager
以键值对的方式存储在manager
中
- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
forTask:(NSURLSessionTask *)task
{
NSParameterAssert(task);
NSParameterAssert(delegate);
[self.lock lock];
// 用taskIdentifier(每个session创建的task的identifier是唯一的)作为key值,存储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;
}
即每个task上的处理交由AFURLSessionManagerTaskDelegate
处理。
其它
_AFURLSessionTaskSwizzling
中采用method swizzling
,交换了系统NSURLSessionTask
的suspend
和resume
方法,分别在两个方法原有的基础上添加了通知。
参考:
chenxianming的博客