Whats
AFNetworking是iOS开发中进行网络数据请求的框架之一。目前大多数的app的网络层都是基于此框架来开发的。而AFNetworking本质上是对NSURLSession(NSURLConnection目前已经废弃)的一层封装,以及对数据delegate的管理,所以了解其原理和思想还是很必要的。
Hows
-
AFNetworkReachabilityManager(网络连接管理模块)
这个模块主要用来监控当前手机所连接的网络的状态。状态包括:未知网络,未连接网络,蜂窝网络,wifi网络。其中的核心的关键应该是用SystemConfiguration中的SCNetworkReachabilityRef来处理的。
1.根据adress初始化一个SCNetworkReachabilityRef
+ (instancetype)manager
{
//1.根据系统的版本来判断是初始化IPV4还是IPV6的adress.
#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 90000) || (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100)
struct sockaddr_in6 address;
bzero(&address, sizeof(address));
address.sin6_len = sizeof(address);
address.sin6_family = AF_INET6;
#else
struct sockaddr_in address;
bzero(&address, sizeof(address));
address.sin_len = sizeof(address);
address.sin_family = AF_INET;
#endif
return [self managerForAddress:&address];
}
+ (instancetype)managerForAddress:(const void *)address {
//2.根据adress初始化SCNetworkReachabilityRef
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)address);
AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability];
CFRelease(reachability);
return manager;
}
或者根据domain初始化一个SCNetworkReachabilityRef
+ (instancetype)managerForDomain:(NSString *)domain {
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [domain UTF8String]);
AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability];
CFRelease(reachability);
return manager;
}
2.启动监听
- (void)startMonitoring {
[self stopMonitoring];
if (!self.networkReachability) {
return;
}
__weak __typeof(self)weakSelf = self;
AFNetworkReachabilityStatusCallback callback = ^(AFNetworkReachabilityStatus status) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
strongSelf.networkReachabilityStatus = status;
if (strongSelf.networkReachabilityStatusBlock) {
strongSelf.networkReachabilityStatusBlock(status);
}
return strongSelf;
};
//1.初始化一个NetworkReachability上下文,注入监听的网络zhuan'tia回调。AFNetworkReachabilityRetainCallback和AFNetworkReachabilityReleaseCallback对callback内存进行管理
SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL};
//2.设置ReachabilityCallback
SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context);
//3.将networkReachability加入到主线程的RunLoop中
SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{
SCNetworkReachabilityFlags flags;
if (SCNetworkReachabilityGetFlags(self.networkReachability, &flags)) {
AFPostReachabilityStatusChange(flags, callback);
}
});
}
static void AFPostReachabilityStatusChange(SCNetworkReachabilityFlags flags, AFNetworkReachabilityStatusCallback block) {
//4.根据flags判断当前的网络状态
AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags);
dispatch_async(dispatch_get_main_queue(), ^{
AFNetworkReachabilityManager *manager = nil;
//5.回调callback,且通过通知将状态告知出去
if (block) {
manager = block(status);
}
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
NSDictionary *userInfo = @{ AFNetworkingReachabilityNotificationStatusItem: @(status) };
[notificationCenter postNotificationName:AFNetworkingReachabilityDidChangeNotification object:manager userInfo:userInfo];
});
}
static void AFNetworkReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkReachabilityFlags flags, void *info) {
AFPostReachabilityStatusChange(flags, (__bridge AFNetworkReachabilityStatusCallback)info);
}
3.关闭监听
- (void)stopMonitoring {
if (!self.networkReachability) {
return;
}
//关闭监听
SCNetworkReachabilityUnscheduleFromRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
}
-
AFSecurityPolicy(安全认证模块)
....
-
AFURLResponseSerialization(响应序列化)
这个模块主要是对请求结果的序列化。它是一个protcol.它的子类通过实现该protcol来处理不同的响应结果。包括:AFHTTPResponseSerializer(HTTP响应序列化基类),AFJSONResponseSerializer(JSON处理),AFXMLParserResponseSerializer(XML解析处理),AFXMLDocumentResponseSerializer(XML文档处理),AFPropertyListResponseSerializer,AFCompoundResponseSerializer。
1.AFHTTPResponseSerializer
初始化一个Serializer
+ (instancetype)serializer {
return [[self alloc] init];
}
- (instancetype)init {
self = [super init];
if (!self) {
return nil;
}
//1.能够接受的response的状态码为200~300之间
self.acceptableStatusCodes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)];
//2.子类决定可以接受的response的内容类型
self.acceptableContentTypes = nil;
return self;
}
处理responseObject并并验证responseObject
- (id)responseObjectForResponse:(NSURLResponse *)response
data:(NSData *)data
error:(NSError *__autoreleasing *)error
{
[self validateResponse:(NSHTTPURLResponse *)response data:data error:error];
return data;
}
//统一验证处理response的contentType和statusCode
- (BOOL)validateResponse:(NSHTTPURLResponse *)response
data:(NSData *)data
error:(NSError * __autoreleasing *)error
{
BOOL responseIsValid = YES;
NSError *validationError = nil;
if (response && [response isKindOfClass:[NSHTTPURLResponse class]]) {
//3.判断response的MIMEType是属于self.acceptableContentTypes里不属于抛出异常
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;
}
//4.判断response的statuscode是属于self.acceptableStatusCodes里不属于抛出异常
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;
}
2.AFJSONResponseSerializer
1.初始化一个JSONResponseSerializer
+ (instancetype)serializer {
return [self serializerWithReadingOptions:(NSJSONReadingOptions)0];
}
+ (instancetype)serializerWithReadingOptions:(NSJSONReadingOptions)readingOptions {
AFJSONResponseSerializer *serializer = [[self alloc] init];
serializer.readingOptions = readingOptions;
return serializer;
}
- (instancetype)init {
self = [super init];
if (!self) {
return nil;
}
//1.指定这里可以接受的response类型
self.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", nil];
return self;
}
2.处理JSONResponse
- (id)responseObjectForResponse:(NSURLResponse *)response
data:(NSData *)data
error:(NSError *__autoreleasing *)error
{
//1.验证response的的contentType和statusCode是否符合条件
if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) {
if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) {
return nil;
}
}
// Workaround for behavior of Rails to return a single space for `head :ok` (a workaround for a bug in Safari), which is not interpreted as valid input by NSJSONSerialization.
// See https://github.com/rails/rails/issues/1742
BOOL isSpace = [data isEqualToData:[NSData dataWithBytes:" " length:1]];
if (data.length == 0 || isSpace) {
return nil;
}
NSError *serializationError = nil;
//2.将json转化为OC对象
id responseObject = [NSJSONSerialization JSONObjectWithData:data options:self.readingOptions error:&serializationError];
if (!responseObject)
{
if (error) {
*error = AFErrorWithUnderlyingError(serializationError, *error);
}
return nil;
}
//3.移除对象中Null值得键值
if (self.removesKeysWithNullValues) {
return AFJSONObjectByRemovingKeysWithNullValues(responseObject, self.readingOptions);
}
return responseObject;
}
removesKeysWithNullValues移除null的键值
3.AFImageResponseSerializer
1.初始化一个图片数据响应的序列化
- (instancetype)init {
self = [super init];
if (!self) {
return nil;
}
//1.可接受的contentType
self.acceptableContentTypes = [[NSSet alloc] initWithObjects:@"image/tiff", @"image/jpeg", @"image/gif", @"image/png", @"image/ico", @"image/x-icon", @"image/bmp", @"image/x-bmp", @"image/x-xbitmap", @"image/x-win-bitmap", nil];
#if TARGET_OS_IOS || TARGET_OS_TV
//2.屏幕的比例因子
self.imageScale = [[UIScreen mainScreen] scale];
self.automaticallyInflatesResponseImage = YES;
#elif TARGET_OS_WATCH
self.imageScale = [[WKInterfaceDevice currentDevice] screenScale];
self.automaticallyInflatesResponseImage = YES;
#endif
return self;
}
2.处理ImageResponse
- (id)responseObjectForResponse:(NSURLResponse *)response
data:(NSData *)data
error:(NSError *__autoreleasing *)error
{
//1.验证response的的contentType和statusCode是否符合条件
if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) {
if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) {
return nil;
}
}
#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
if (self.automaticallyInflatesResponseImage) {
//2.通过在后台生成bitmap的形式来解压缩图片生成UIimage
return AFInflatedImageFromResponseWithDataAtScale((NSHTTPURLResponse *)response, data, self.imageScale);
} else {
//3.直接通过data生成图片
return AFImageWithDataAtScale(data, self.imageScale);
}
#else
// Ensure that the image is set to it's correct pixel width and height
NSBitmapImageRep *bitimage = [[NSBitmapImageRep alloc] initWithData:data];
NSImage *image = [[NSImage alloc] initWithSize:NSMakeSize([bitimage pixelsWide], [bitimage pixelsHigh])];
[image addRepresentation:bitimage];
return image;
#endif
return nil;
}
-
AFURLSessionManager(封装NSURLSession管理模块)
初始化一个AFURLSessionManager
- (instancetype)init {
return [self initWithSessionConfiguration:nil];
}
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
self = [super init];
if (!self) {
return nil;
}
if (!configuration) {
configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
}
self.sessionConfiguration = configuration;
//1.初始化一个串行队列作为NSURLSession处理队列
self.operationQueue = [[NSOperationQueue alloc] init];
self.operationQueue.maxConcurrentOperationCount = 1;
//2.默认ResponseSerializer为AFJSONResponseSerializer
self.responseSerializer = [AFJSONResponseSerializer serializer];
self.securityPolicy = [AFSecurityPolicy defaultPolicy];
#if !TARGET_OS_WATCH
self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
#endif
//3.记录保存正在执行的TaskDelegate
self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];
//4.线程锁
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;
}
其中mutableTaskDelegatesKeyedByTaskIdentifier为一个记录当前正在执行的task的容器,task执行的时候加入,task执行结束的时候从mutableTaskDelegatesKeyedByTaskIdentifier移除。
AFURLSessionManager同时实现了NSURLSession的各种task的代理包括:(NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate)负责全局的验证和task执行的状态向外回调。但是AFURLSessionManager不负责数据的接受组装和任务执行进度监控,这些工作都交由AFURLSessionManagerTaskDelegate负责
task结束后对对数据进行结果的回调
- (void)URLSession:(__unused NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
__strong AFURLSessionManager *manager = self.manager;
__block id responseObject = nil;
__block NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
userInfo[AFNetworkingTaskDidCompleteResponseSerializerKey] = manager.responseSerializer;
//Performance Improvement from #2672
NSData *data = nil;
if (self.mutableData) {
data = [self.mutableData copy];
//We no longer need the reference, so nil it out to gain back some memory.
self.mutableData = nil;
}
#if AF_CAN_USE_AT_AVAILABLE && AF_CAN_INCLUDE_SESSION_TASK_METRICS
if (@available(iOS 10, macOS 10.12, watchOS 3, tvOS 10, *)) {
if (self.sessionTaskMetrics) {
userInfo[AFNetworkingTaskDidCompleteSessionTaskMetrics] = self.sessionTaskMetrics;
}
}
#endif
if (self.downloadFileURL) {
userInfo[AFNetworkingTaskDidCompleteAssetPathKey] = self.downloadFileURL;
} else if (data) {
userInfo[AFNetworkingTaskDidCompleteResponseDataKey] = data;
}
if (error) {
userInfo[AFNetworkingTaskDidCompleteErrorKey] = error;
//添加异步调度组来进行回调
dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{
if (self.completionHandler) {
self.completionHandler(task.response, responseObject, error);
}
//通过主线程的将通知发送出去
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
});
});
} else {
//异步并行对列处理数据的反序列化
dispatch_async(url_session_manager_processing_queue(), ^{
NSError *serializationError = nil;
responseObject = [manager.responseSerializer responseObjectForResponse:task.response data:data error:&serializationError];
if (self.downloadFileURL) {
responseObject = self.downloadFileURL;
}
if (responseObject) {
userInfo[AFNetworkingTaskDidCompleteSerializedResponseKey] = responseObject;
}
if (serializationError) {
userInfo[AFNetworkingTaskDidCompleteErrorKey] = serializationError;
}
dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{
if (self.completionHandler) {
self.completionHandler(task.response, responseObject, serializationError);
}
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
});
});
});
}
}
这里采用多线程的方式处理数据有个值得注意的地方:初始化session的时候operation的maxConcurrentOperationCount = 1保证了已经delegate处理数据为串行队列,但这里为什么completionGroup是?completionGroup是为了让调用者能够捕获到completionHandler完成后通知,url_session_manager_processing_queue()这个并发队列异步处理反序列化,避免柱塞当前线程,提高线程的利用率
还用一个地方是_AFURLSessionTaskSwizzling。这个类主要是通过hook NSURLSessionTask的suspend,resume来回调通知task的开始执行和挂起。
-
AFURLRequestSerialization(请求序列化模块)
该模块主要是请求的序列化,AFURLRequestSerialization为接口类,其他子类主要是实现其中的接口来达到不同请求方式的序列化。主要的方法为:
- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
withParameters:(id)parameters
error:(NSError *__autoreleasing *)error
{
NSParameterAssert(request);
NSMutableURLRequest *mutableRequest = [request mutableCopy];
[self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) {
if (![request valueForHTTPHeaderField:field]) {
[mutableRequest setValue:value forHTTPHeaderField:field];
}
}];
NSString *query = nil;
//1.将参数进行序列化,queryStringSerialization提供了自定义的参数序列化方式,如果为空,则AFQueryStringFromParameters使用默认进行序列化。
if (parameters) {
if (self.queryStringSerialization) {
NSError *serializationError;
query = self.queryStringSerialization(request, parameters, &serializationError);
if (serializationError) {
if (error) {
*error = serializationError;
}
return nil;
}
} else {
switch (self.queryStringSerializationStyle) {
case AFHTTPRequestQueryStringDefaultStyle:
query = AFQueryStringFromParameters(parameters);
break;
}
}
}
//2.这里进行拼接查询还是进行body查询
if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) {
if (query && query.length > 0) {
mutableRequest.URL = [NSURL URLWithString:[[mutableRequest.URL absoluteString] stringByAppendingFormat:mutableRequest.URL.query ? @"&%@" : @"?%@", query]];
}
} else {
// #2864: an empty string is a valid x-www-form-urlencoded payload
if (!query) {
query = @"";
}
if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) {
[mutableRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
}
[mutableRequest setHTTPBody:[query dataUsingEncoding:self.stringEncoding]];
}
return mutableRequest;
}
其中AFQueryStringFromParameters用来对参数进行序列化,AFPercentEscapedStringFromString对参数进行百分号编码可以作为我们日常开发的工具。这里其实是有一个容易忽略的坑点:
//OC的参数形式
NSDictionary *dict = @{@"people":@[@{@"wang":@"27"},
@{@"li":@"30"}]};
//后端希望的参数形式
people[0]["wang"]="27"&people[1]["li"]="30"
//真实后端接收到的
people[]["wang"]="27"&people[]["li"]="30"
上面就是参数中存在数组的时候可能存在的坑点。所以这里目前的解决方案是queryStringSerialization这个block来进行自定义处理。
请求序列化这里还有就是就是对multipart的处理。还有就是AFJSONRequestSerializer和AFPropertyListRequestSerializer其实就是对body转化为JSON和PropertyList进行请求。
-
AFHTTPSessionManager(HTTP请求封装模块)
AFHTTPSessionManager继承AFURLSessionManager,负责对HTTP请求的包装,包括:(GET,POST,HEAD,PUT,PATCH,DELETE)
- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
headers:(NSDictionary *)headers
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress
success:(void (^)(NSURLSessionDataTask *, id))success
failure:(void (^)(NSURLSessionDataTask *, NSError *))failure
{
NSError *serializationError = nil;
//1.进行请求序列化,添加自定义的请求头
NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
for (NSString *headerField in headers.keyEnumerator) {
[request addValue:headers[headerField] forHTTPHeaderField:headerField];
}
if (serializationError) {
if (failure) {
dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
failure(nil, serializationError);
});
}
return nil;
}
//2.调用AFURLSessionManager进行组装Task
__block NSURLSessionDataTask *dataTask = nil;
dataTask = [self dataTaskWithRequest:request
uploadProgress:uploadProgress
downloadProgress:downloadProgress
completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
if (error) {
if (failure) {
failure(dataTask, error);
}
} else {
if (success) {
success(dataTask, responseObject);
}
}
}];
return dataTask;
}