开源库信息

AFNetWorking 源码解析

AFNetWorking 组成

AFNetWorking 主要由如下图几个部分构成

  • AFURLSessionManager

AFURLSessionManager 是整个开源库的核心,它连接着AFNetWorking其他几个重要部分,它是AFHTTPSessionManager的父类,一般我们在使用的时候一般使用AFHTTPSessionManager。但是核心部分还是集中在AFURLSessionManager中。AFURLSessionManager遵循了NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate一大堆的协议,并将AFHTTPSessionManager作为URLSession 的 delegate。这样在URLSession 触发一系列关键事件的时候,够可以交给AFURLSessionManager接管处理。

  • AFHTTPRequestSerializer
  • AFHTTPResponseSerializer

AFHTTPRequestSerializer,AFHTTPResponseSerializer 分别是请求序列化器和返回体序列化器,引入序列化器后,序列化器就相当于一个插件一样,这样做的好处不言而喻,增加了整个系统的灵活性,比如我们应用中可能会对接不同的后端,这些后端可能有着不同的数据交付格式,有了序列化器后就可以针对不同的后端数据交付格式实现一对序列化器。整个框架就显得十分灵活,AFNetworking 也根据常见的需求实现了一些常用的序列化器,例如 AFJSONRequestSerializer,AFPropertyListRequestSerializer这两类请求序列化器;AFJSONResponseSerializer,AFXMLParserResponseSerializer,AFXMLDocumentResponseSerializer,
AFPropertyListResponseSerializer,AFImageResponseSerializer,AFCompoundResponseSerializer 这几类返回体序列化器。

  • AFNetworkReachabilityManager

AFNetworkReachabilityManager 主要用于检测网络可用性,这对于应用来说也是非常常用的一项功能。

  • AFSecurityPolicy

AFSecurityPolicy 主要用于提供安全认证相关的处理,

AFNetWorking 框架总览

下面是AFNetWorking 整个框架重要流程的大致结构图,下面将针对这张图对源码进行进一步解析:

  • AFURLSessionManager的组成

上面提到AFURLSessionManager是整个AFNetWorking的核心部分,在iOS中我们如果需要执行网络请求需要URLSession,AFNetWorking也一样,它只不过是对URLSession的一个封装,最核心的部分还是借助URLSession来完成,因此我们最先要弄清楚AFURLSessionManager是如何串起来的,我们上面提到了AFURLSessionManager实现了一系列的协议,并作为URLSession的delegate。这样我们在使用URLSession进行网络请求的时候就会触发delegate的对应方法进行处理,从而将流程交接给AFURLSessionManager。然后再由AFURLSessionManager调用其他的部件对数据进行后续处理。我们来看下AFURLSessionManager的初始化代码,看下AFURLSessionManager是由哪些部分组成:

- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {

//.......

// sessionConfiguration URLSession 配置类,通过它可以对URLSession进行配置
if (!configuration) {
configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
}
self.sessionConfiguration = configuration;

//operationQueue:代理执行的OperationQueue,通过maxConcurrentOperationCount 限制每次只执行一个任务。
self.operationQueue = [[NSOperationQueue alloc] init];
self.operationQueue.maxConcurrentOperationCount = 1;

//session: AFURLSessionManager 最核心的部分,在这里将AFURLSessionManager 作为NSURLSession delegate,并指定代理的执行队列
self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];

//指定返回体序列化器
self.responseSerializer = [AFJSONResponseSerializer serializer];

//指定安全认证相关类
self.securityPolicy = [AFSecurityPolicy defaultPolicy];

//初始化网络状态检测对象
self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];

//这个是task与AFURLSessionManagerTaskDelegate映射的表格,AFURLSessionManagerTaskDelegate后面会详细介绍。
self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];

//.....

return self;
}

在初始化方法中,主要初始化了self.session,self.responseSerializer,self.securityPolicy,self.reachabilityManager 这些对象,并给self.session指定了delegate,delegate执行的队列,以及配置。

介绍了AFURLSessionManager接下来就按照应用场景对AFNetWorking进行介绍:

  • 发起数据请求

这部分我们会以常见的GET请求为例子来过下整个流程:

- (NSURLSessionDataTask *)GET:(NSString *)URLString
parameters:(id)parameters
progress:(void (^)(NSProgress * _Nonnull))downloadProgress
success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure {

NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"GET"
URLString:URLString
parameters:parameters
uploadProgress:nil
downloadProgress:downloadProgress
success:success
failure:failure];

[dataTask resume];
return dataTask;
}

在GET中主要通过dataTaskWithHTTPMethod创建了一个NSURLSessionDataTask对象,然后通过resume执行这个task。

- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
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;
NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
if (serializationError) {
if (failure) {
dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
failure(nil, serializationError);
});
}

return nil;
}

__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;
}

dataTaskWithHTTPMethod 方法中主要分成两大部分:

1. 构建NSMutableURLRequest
2. 构建NSURLSessionDataTask
  • 构建NSMutableURLRequest
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
error:(NSError *__autoreleasing *)error {
//....
//使用URLString 创建 NSURL
NSURL *url = [NSURL URLWithString:URLString];

//url 创建 NSMutableURLRequest
NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url];
//NSMutableURLRequest method
mutableRequest.HTTPMethod = method;

//将属性映射到NSMutableURLRequest
for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
if ([self.mutableObservedChangedKeyPaths containsObject:keyPath]) {
[mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath];
}
}
//将参数添加到NSMutableURLRequest
mutableRequest = [[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy];

return mutableRequest;
}

NSMutableURLRequest 主要由NSURL,HTTPMethod,HTTPBody,allHTTPHeaderFields,parameters 以及一些配置属性构成。这里有个比较关键的点,如何将对当前属性的设置同步到mutableRequest中。这里用的是KVO来实现,下面这部分的关键代码:

for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
if ([self.mutableObservedChangedKeyPaths containsObject:keyPath]) {
[mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath];
}
}

首先会遍历AFHTTPRequestSerializerObservedKeyPaths,如果有在mutableObservedChangedKeyPaths中,mutableRequest就对这个属性进行监听。下面是AFHTTPRequestSerializerObservedKeyPaths的定义:

static NSArray * AFHTTPRequestSerializerObservedKeyPaths() {
static NSArray *_AFHTTPRequestSerializerObservedKeyPaths = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_AFHTTPRequestSerializerObservedKeyPaths = @[

NSStringFromSelector(@selector(allowsCellularAccess)),
NSStringFromSelector(@selector(cachePolicy)),
NSStringFromSelector(@selector(HTTPShouldHandleCookies)),
NSStringFromSelector(@selector(HTTPShouldUsePipelining)),
NSStringFromSelector(@selector(networkServiceType)),
NSStringFromSelector(@selector(timeoutInterval))

];
});

return _AFHTTPRequestSerializerObservedKeyPaths;
}

那么mutableObservedChangedKeyPaths是怎么来的?这部分在AFHTTPRequestSerializer请求序列化器的初始化方法中有做处理,我们看下这部分代码:

- (instancetype)init {

//.......
// 指定字符编码格式
self.stringEncoding = NSUTF8StringEncoding;

// 用于存储请求头
self.mutableHTTPRequestHeaders = [NSMutableDictionary dictionary];

// 请求头更新队列
self.requestHeaderModificationQueue = dispatch_queue_create("requestHeaderModificationQueue", DISPATCH_QUEUE_CONCURRENT);

// --- Accept-Language 设置 ----

// Accept-Language HTTP Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
NSMutableArray *acceptLanguagesComponents = [NSMutableArray array];
[[NSLocale preferredLanguages] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
float q = 1.0f - (idx * 0.1f); /*0 , 1 ,2 ,3 ,4 */
[acceptLanguagesComponents addObject:[NSString stringWithFormat:@"%@;q=%0.1g", obj, q]];
*stop = q <= 0.5f;
}];
[self setValue:[acceptLanguagesComponents componentsJoinedByString:@", "] forHTTPHeaderField:@"Accept-Language"];

// ----- User-Agent 设置 -------
NSString *userAgent = nil;
// User-Agent Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.43
userAgent = [NSString stringWithFormat:@"%@/%@ (%@; iOS %@; Scale/%0.2f)", [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleExecutableKey] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleIdentifierKey], [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleVersionKey], [[UIDevice currentDevice] model], [[UIDevice currentDevice] systemVersion], [[UIScreen mainScreen] scale]];

if (userAgent) {
if (![userAgent canBeConvertedToEncoding:NSASCIIStringEncoding]) {
NSMutableString *mutableUserAgent = [userAgent mutableCopy];
if (CFStringTransform((__bridge CFMutableStringRef)(mutableUserAgent), NULL, (__bridge CFStringRef)@"Any-Latin; Latin-ASCII; [:^ASCII:] Remove", false)) {
userAgent = mutableUserAgent;
}
}
[self setValue:userAgent forHTTPHeaderField:@"User-Agent"];
}

// ------ 指定哪些请求的parameter添加到URL上 -------
// HTTP Method Definitions; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
self.HTTPMethodsEncodingParametersInURI = [NSSet setWithObjects:@"GET", @"HEAD", @"DELETE", nil];

// ------- 通过keyPath 方式设置 -------
self.mutableObservedChangedKeyPaths = [NSMutableSet set];
for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
if ([self respondsToSelector:NSSelectorFromString(keyPath)]) {
[self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:AFHTTPRequestSerializerObserverContext];
}
}
return self;
}

这里主要对请求的字符串编码格式,请求头进行设置,以及通过keyPath方式往mutableObservedChangedKeyPaths中添加要监听的keyPath。KVO 方式监听的方式是NSKeyValueObservingOptionNew,也就是这些被监听的属性新建的时候就会被通知,我们接下来看下收到通知后的处理:

- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(__unused id)object
change:(NSDictionary *)change
context:(void *)context {
if (context == AFHTTPRequestSerializerObserverContext) {
if ([change[NSKeyValueChangeNewKey] isEqual:[NSNull null]]) {
[self.mutableObservedChangedKeyPaths removeObject:keyPath];
} else {
[self.mutableObservedChangedKeyPaths addObject:keyPath];
}
}
}

看到这里大家就可以明白了mutableObservedChangedKeyPaths是怎么来的:一旦我们监听的属性被创建后,就会跑到observeValueForKeyPath中,在observeValueForKeyPath方法中,会根据该属性是否为nil来决定是从mutableObservedChangedKeyPaths删除还是添加到mutableObservedChangedKeyPaths中。

我们这里对这部分做个总结:
在AFHTTPRequestSerializer请求序列化器初始化过程中会对AFHTTPRequestSerializerObservedKeyPaths中指定的属性通过KVO进行监听,监听这些对象的新建事件,一旦新建就会添加到mutableObservedChangedKeyPaths,然后每次发起请求前构造NSMutableRequest的时候,对存在于mutableObservedChangedKeyPaths中的属性进行KVO监听。这样一旦我们设置了序列化器中的对应属性,这些属性的状态就会同步到NSMutableRequest中。

我们接下来再回到请求的构建过程中:

- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
withParameters:(id)parameters
error:(NSError *__autoreleasing *)error {
NSParameterAssert(request);

//复制一份request
NSMutableURLRequest *mutableRequest = [request mutableCopy];

//将原始的Header添加到新的request
[self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) {
if (![request valueForHTTPHeaderField:field]) {
[mutableRequest setValue:value forHTTPHeaderField:field];
}
}];

NSString *query = nil;
if (parameters) {
if (self.queryStringSerialization) {
NSError *serializationError;
query = self.queryStringSerialization(request, parameters, &serializationError);
if (serializationError) {
if (error) {
//通过error传出
*error = serializationError;
}
return nil;
}
} else {
switch (self.queryStringSerializationStyle) {
case AFHTTPRequestQueryStringDefaultStyle:
//将参数转换成key1 = value1 & key2 = value2的形式
query = AFQueryStringFromParameters(parameters);
break;
}
}
}
//如果需要将参数添加到URL最尾部,默认`GET`, `HEAD`, `DELETE` 这些是需要将参数添加到URL尾部的
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"];
}
//将参数添加到body部分
[mutableRequest setHTTPBody:[query dataUsingEncoding:self.stringEncoding]];
}
return mutableRequest;
}

在这部分中我们会将初始化序列化器方法中指定的UA Accept-Language 这些头信息放置到请求中。
接着根据queryStringSerialization来决定需要对parameters进行序列化处理还是转换成“key1 = value1 & key2 = value2的形式”形式。再根据self.HTTPMethodsEncodingParametersInURI决定是将参数放到url上还是body中。到此为止请求对象构建完毕。

  • 构建NSURLSessionDataTask
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler {

__block NSURLSessionDataTask *dataTask = nil;
url_session_manager_create_task_safely(^{
//通过一个request让session创建一个dataTask
dataTask = [self.session dataTaskWithRequest:request];
});
//为这个dataTask添加uploadProgressBlock,downloadProgressBlock,completionHandler 并创建一个AFURLSessionManagerTaskDelegate与dataTask关联
[self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];
return dataTask;
}

NSURLSessionDataTask的创建是通过URLSession创建并管理的,要创建NSURLSessionDataTask需要将上个步骤创建的NSMutableRequest传给URLSession通过dataTaskWithRequest方法返回NSURLSessionDataTask实例,然后再通过addDelegateForDataTask,往task中添加
uploadProgressBlock,downloadProgressBlock,completionHandler 这些都是AFNetWorking向外面传递数据的接口,我们接下来看下addDelegateForDataTask

- (void)addDelegateForDataTask:(NSURLSessionDataTask *)dataTask
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler {

//新建一个AFURLSessionManagerTaskDelegate每个AFURLSessionManagerTaskDelegate持有uploadProgressBlock,downloadProgressBlock,completionHandler以及AFURLSessionManager
AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:dataTask];
delegate.manager = self;
delegate.completionHandler = completionHandler;

dataTask.taskDescription = self.taskDescriptionForSessionTasks;

//将taskidentify 作为key delegate为value 存到 mutableTaskDelegatesKeyedByTaskIdentifier字典中
[self setDelegate:delegate forTask:dataTask];

delegate.uploadProgressBlock = uploadProgressBlock;
delegate.downloadProgressBlock = downloadProgressBlock;
}

在这个方法中会创建一个AFURLSessionManagerTaskDelegate,每个NSURLSessionDataTask都会与一个AFURLSessionManagerTaskDelegate相关联,这是通过****[self setDelegate:delegate forTask:dataTask]****来完成的,在setDelegate方法中将taskidentify 作为key delegate为value 存到 mutableTaskDelegatesKeyedByTaskIdentifier字典中。
AFURLSessionManagerTaskDelegate主要负责两个任务,一个是负责进度的更新,一个是的网络数据mutableData的管理。这个会在后面进行介绍。每个AFURLSessionManagerTaskDelegate持有uploadProgressBlock,downloadProgressBlock,completionHandler以及AFURLSessionManager,在进度发生变化的时候都会通过uploadProgressBlock,downloadProgressBlock传出,当网络数据结束后,通过completionHandler传出。

那么AFURLSessionManagerTaskDelegate又是怎么和AFURLSessionManager产生关联的?
我们上面提到,所有的事件源于URLSession的各个代理,而通过将AFURLSessionManager设置为URLSession从而将事件传递到AFURLSessionManager,那么怎么将这些事件传给AFURLSessionManagerTaskDelegate呢?

- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error {
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];
// delegate may be nil when completing a task in the background
if (delegate) {
[delegate URLSession:session task:task didCompleteWithError:error];
[self removeDelegateForTask:task];
}
if (self.taskDidComplete) {
self.taskDidComplete(session, task, error);
}
}

这就涉及到上面提到的mutableTaskDelegatesKeyedByTaskIdentifier,我们每个dataTask被新建的时候,都会同时新建一个AFURLSessionManagerTaskDelegate,并添加到mutableTaskDelegatesKeyedByTaskIdentifier,建立起以taskidentify为key AFURLSessionManagerTaskDelegate为value的映射关系。我们看上面的代理方法,会将task作为参数传进来,来表示具体是哪个task的回调,这时候通过task就可以找到对应的AFURLSessionManagerTaskDelegate 对象,并调用对应的方法进行处理,这就完成了AFURLSessionManager向AFURLSessionManagerTaskDelegate关联的环节。

  • 接受数据请求,交付数据

在介绍这部分之前我们先来看下NSURLSessionDataDelegate

#pragma mark - NSURLSessionDataDelegate

//接收到服务器响应后会先调用这个方法,在这个方法中判定该次任务是否继续执行,或者转化为其他类型的任务

- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler{

/**
判定该次任务是否继续执行,或者转化为其他类型的任务
typedef NS_ENUM(NSInteger, NSURLSessionResponseDisposition) {
NSURLSessionResponseCancel = 0, //取消本次task任务
NSURLSessionResponseAllow = 1, //本次task任务继续
NSURLSessionResponseBecomeDownload = 2, //转变本次dataTask任务为一个downloadTask下载任务
NSURLSessionResponseBecomeStream //转变本次dataTask任务为一个StreamTask流任务
} NS_ENUM_AVAILABLE(NSURLSESSION_AVAILABLE, 7_0);
*/
//允许本次task继续执行
completionHandler(NSURLSessionResponseAllow);

}

// 数据传输的过程中该方法会被调用 如果返回数据特别长,该方法会被多次调用
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data {
//拼接返回的数据
[self.receiveData appendData:data];
}

//数据传输完成最后该方法会被调用 不管最后该次请求成功或者失败该方法都会调用
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
if(error){
// 请求失败
NSLog(@"error = %@\n",error);
} else {
// 请求成功
//解析返回的数据
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:self.receiveData options:NSJSONReadingMutableContainers | NSJSONReadingAllowFragments error:nil];
NSLog(@"response content = %@",dic);
}
}

在收到数据的时候会首先调用URLSession:dataTask:didReceiveResponse:completionHandler这个代理方法,可以在这个方法中根据返回的response来决定该任务是继续执行,还是转化为其他类型的任务。然后在 URLSession:dataTask:didReceiveData中接送回传的数据,最后走 URLSession: task: didCompleteWithError 对数据进行交付。

我们紧接着就来看下AFNetWorking中是如何处理这部分流程的:

URLSession:dataTask:didReceiveResponse:completionHandler 方法中,AFURLSessionManager会通过block介入整个流程来决定到底是继续执行还是转换为其他类型任务。

- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {

NSURLSessionResponseDisposition disposition = NSURLSessionResponseAllow;
if (self.dataTaskDidReceiveResponse) {
disposition = self.dataTaskDidReceiveResponse(session, dataTask, response);
}
if (completionHandler) {
completionHandler(disposition);
}
}

在接到数据后先通过delegateForTask方法拿到当前task对应的AFURLSessionManagerTaskDelegate,然后交给它进行处理。

- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data {

AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask];
[delegate URLSession:session dataTask:dataTask didReceiveData:data];

if (self.dataTaskDidReceiveData) {
self.dataTaskDidReceiveData(session, dataTask, data);
}
}

在NSURLSessionDataDelegate 中将该次到达的数据通过appendData添加到self.mutableData,到数据接收完毕后就会将self.mutableData交付出去。

- (void)URLSession:(__unused NSURLSession *)session
dataTask:(__unused NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data {

self.downloadProgress.totalUnitCount = dataTask.countOfBytesExpectedToReceive;
self.downloadProgress.completedUnitCount = dataTask.countOfBytesReceived;

[self.mutableData appendData:data];
}

等到数据接收结束后会回调URLSession: task: didCompleteWithError这里同样会将流程转到task对应的AFURLSessionManagerTaskDelegate进行处理,最后将task从字典中移除。

- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error {
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];
// delegate may be nil when completing a task in the background
if (delegate) {
[delegate URLSession:session task:task didCompleteWithError:error];
[self removeDelegateForTask:task];
}
if (self.taskDidComplete) {
self.taskDidComplete(session, task, error);
}
}

在AFURLSessionManagerTaskDelegate中会将数据传递给responseSerializer,对数据进行预先处理后,通过bock以及通知将数据交付给应用层。

- (void)URLSession:(__unused NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error {

// ....

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;
//使用responseSerializer 进行处理
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];
});
});
});
}
}

我们看下返回体序列化器的处理过程,这里以最常用的AFJSONResponseSerializer来进行分析:

- (id)responseObjectForResponse:(NSURLResponse *)response
data:(NSData *)data
error:(NSError *__autoreleasing *)error {
if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) {
if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) {
return nil;
}
}
//....
NSError *serializationError = nil;

id responseObject = [NSJSONSerialization JSONObjectWithData:data options:self.readingOptions error:&serializationError];

//.....

return responseObject;
}

responseObjectForResponse 方法就完成两件事情:

1. 对返回response数据进行合法性校验
2. 对NSData 进行对应处理后(序列化)后返回

在validateResponse 中主要完成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]]) {
//对返回体中的contentType 进行校验
if (self.acceptableContentTypes && ![self.acceptableContentTypes containsObject:[response MIMEType]] &&
!([response MIMEType] == nil && [data length] == 0)) {
if ([data length] > 0 && [response URL]) {
//.....
}
responseIsValid = NO;
}
//对返回体中的StatusCodes进行校验
if (self.acceptableStatusCodes && ![self.acceptableStatusCodes containsIndex:(NSUInteger)response.statusCode] && [response URL]) {
//.....
responseIsValid = NO;
}
}

if (error && !responseIsValid) {
*error = validationError;
}
return responseIsValid;
}
  • 进度的更新

在上传数据或者下载数据的时候会分别回调didSendBodyData,didWriteData进行处理,在这两个代理回调中都会将数据传递到AFURLSessionManagerTaskDelegate中。

- (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {

AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask];
if (delegate) {
[delegate URLSession:session downloadTask:downloadTask didWriteData:bytesWritten totalBytesWritten:totalBytesWritten totalBytesExpectedToWrite:totalBytesExpectedToWrite];
}

if (self.downloadTaskDidWriteData) {
self.downloadTaskDidWriteData(session, downloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
}
}

- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
didSendBodyData:(int64_t)bytesSent
totalBytesSent:(int64_t)totalBytesSent
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend {

//如果返回的数据不知道大小,则从Content-Length字段中获取。
int64_t totalUnitCount = totalBytesExpectedToSend;
if(totalUnitCount == NSURLSessionTransferSizeUnknown) {
NSString *contentLength = [task.originalRequest valueForHTTPHeaderField:@"Content-Length"];
if(contentLength) {
totalUnitCount = (int64_t) [contentLength longLongValue];
}
}
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];
if (delegate) {
[delegate URLSession:session task:task didSendBodyData:bytesSent totalBytesSent:totalBytesSent totalBytesExpectedToSend:totalBytesExpectedToSend];
}

if (self.taskDidSendBodyData) {
self.taskDidSendBodyData(session, task, bytesSent, totalBytesSent, totalUnitCount);
}
}

在AFURLSessionManagerTaskDelegate中分别更新self.uploadProgress以及self.downloadProgress

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didSendBodyData:(int64_t)bytesSent
totalBytesSent:(int64_t)totalBytesSent
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend{

self.uploadProgress.totalUnitCount = task.countOfBytesExpectedToSend;
self.uploadProgress.completedUnitCount = task.countOfBytesSent;
}

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{

self.downloadProgress.totalUnitCount = totalBytesExpectedToWrite;
self.downloadProgress.completedUnitCount = totalBytesWritten;
}

但是我们并没看到进度数据的交付啊,这部分其实是在初始化AFURLSessionManagerTaskDelegate的时候利用KVO将进度数据与对应的Block的调用进行了关联:

- (instancetype)initWithTask:(NSURLSessionTask *)task {

//.....
_uploadProgress = [[NSProgress alloc] initWithParent:nil userInfo:nil];
_downloadProgress = [[NSProgress alloc] initWithParent:nil userInfo:nil];
__weak __typeof__(task) weakTask = task;
for (NSProgress *progress in @[ _uploadProgress, _downloadProgress ]){
progress.totalUnitCount = NSURLSessionTransferSizeUnknown;
progress.cancellable = YES;

//.....
[progress addObserver:self
forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
options:NSKeyValueObservingOptionNew
context:NULL];
}
return self;
}

在initWithTask中利用KVO监听progress 的 fractionCompleted。一旦有数据变动,都会触发KVO:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
if ([object isEqual:self.downloadProgress]) {
if (self.downloadProgressBlock) {
self.downloadProgressBlock(object);
}
}
else if ([object isEqual:self.uploadProgress]) {
if (self.uploadProgressBlock) {
self.uploadProgressBlock(object);
}
}
}

在observeValueForKeyPath中调用对应的downloadProgressBlock以及uploadProgressBlock 进行数据交付。
扯个不是非常必要的一个问题:为什么需要AFURLSessionManagerTaskDelegateAFURLSessionManagerTaskDelegate
的职责是什么?直接说答案吧:AFURLSessionManagerTaskDelegate 主要处理与task相关的代理,因为不同的task有不同的进度,不同task完成数据接收的时刻也不同,AFURLSessionManagerTaskDelegate就是用来与task相关的代理。

  • resume && suspend 请求

这部分主要在调用默认的resume以及suspend方法的时候增加AFNSURLSessionTaskDidResumeNotificationAFNSURLSessionTaskDidSuspendNotification的通知,实现方式是通过在load方法中替换resume以及suspand的实现,为自己的af_resume以及af_suspend,在这里添加对应的通知。那么为什么要添加这两个通知?我们在介绍任务创建的时候会调用setDelegate:forTask方法。在这里会调用****[self addNotificationObserverForTask:task]****

- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
forTask:(NSURLSessionTask *)task {
[self.lock lock];
self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
[self addNotificationObserverForTask:task];
[self.lock unlock];
}

在addNotificationObserverForTask方法中会让NSURLSessionTask监听AFNSURLSessionTaskDidResumeNotification,以及AFNSURLSessionTaskDidSuspendNotification

- (void)addNotificationObserverForTask:(NSURLSessionTask *)task {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidResume:) name:AFNSURLSessionTaskDidResumeNotification object:task];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidSuspend:) name:AFNSURLSessionTaskDidSuspendNotification object:task];
}

在这里会将task通过通知传递出去,交给业务层进行处理:

- (void)taskDidResume:(NSNotification *)notification {
NSURLSessionTask *task = notification.object;
if ([task respondsToSelector:@selector(taskDescription)]) {
if ([task.taskDescription isEqualToString:self.taskDescriptionForSessionTasks]) {
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidResumeNotification object:task];
});
}
}
}

- (void)taskDidSuspend:(NSNotification *)notification {
NSURLSessionTask *task = notification.object;
if ([task respondsToSelector:@selector(taskDescription)]) {
if ([task.taskDescription isEqualToString:self.taskDescriptionForSessionTasks]) {
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidSuspendNotification object:task];
});
}
}
}
  • 通过 AFSecurityPolicy 保证请求安全

AFSecurityPolicy AFSecurityPolicy 作为 AFURLSessionManager一个主要的组件,主要用于验证 HTTPS 请求的证书是否有效。它有三种模式:

typedef NS_ENUM(NSUInteger, AFSSLPinningMode) {
AFSSLPinningModeNone,
AFSSLPinningModePublicKey,
AFSSLPinningModeCertificate,
};
* AFSSLPinningModeNone          不使用****pinned certificates****进行认证,只会在系统的信任的证书列表中对服务端返回的证书进行验证
* AFSSLPinningModeCertificate 需要客户端保存服务端的证书
* AFSSLPinningModePublicKey 也需要预先保存服务端发送的证书,但是这里只会验证证书中的公钥是否正确

我们先来看下在AFURLSessionManager中什么时机使用AFSecurityPolicy,在发起某个请求的时候如果需要认证的时候会回调NSURLSession中的didReceiveChallenge方法,同样这里也会将该处理转发给AFURLSessionManager,下面是AFURLSessionManager对didReceiveChallenge的处理:

- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler {

NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
__block NSURLCredential *credential = nil;

//这里会将处理流程转到taskDidReceiveAuthenticationChallenge,通过业务层对认证进行处理,并返回disposition

if (self.taskDidReceiveAuthenticationChallenge) {
disposition = self.taskDidReceiveAuthenticationChallenge(session, task, challenge, &credential);
} else {
//如果SecTrustRef validation 是必须对就走下面的流程:
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
//调用evaluateServerTrust方法进行处理
if ([self.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
//如果认证成功生成disposition,credential
disposition = NSURLSessionAuthChallengeUseCredential;
credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
} else {
disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
}
} else {
disposition = NSURLSessionAuthChallengePerformDefaultHandling;
}
}
//将生成的disposition,以及credential传递出去
if (completionHandler) {
completionHandler(disposition, credential);
}
}

所以整个环节中最重要的就是evaluateServerTrust方法了,在看这个方法之前我们先看下AFSecurityPolicy是怎么初始化的:

如果我们没有人为指定证书文件,AFNetWorking 会使用defaultPolicy

+ (instancetype)defaultPolicy {
AFSecurityPolicy *securityPolicy = [[self alloc] init];
securityPolicy.SSLPinningMode = AFSSLPinningModeNone;
return securityPolicy;
}

defaultPolicy实现十分简单,就是创建了一个AFSecurityPolicy对象后指定对应的SSLPinningMode为AFSSLPinningModeNone。

紧接着我们看下evaluateServerTrust这个方法,关键的地方已经加了注释,大家可以对照注释进行理解,这里就不再展开介绍了:

- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust
forDomain:(NSString *)domain {
if (domain && self.allowInvalidCertificates && self.validatesDomainName && (self.SSLPinningMode == AFSSLPinningModeNone || [self.pinnedCertificates count] == 0)) {
// https://developer.apple.com/library/mac/documentation/NetworkingInternet/Conceptual/NetworkingTopics/Articles/OverridingSSLChainValidationCorrectly.html
// According to the docs, you should only trust your provided certs for evaluation.
// Pinned certificates are added to the trust. Without pinned certificates,
// there is nothing to evaluate against.
//
// From Apple Docs:
// "Do not implicitly trust self-signed certificates as anchors (kSecTrustOptionImplicitAnchors).
// Instead, add your own (self-signed) CA certificate to the list of trusted anchors."
NSLog(@"In order to validate a domain name for self signed certificates, you MUST use pinning.");
return NO;
}

NSMutableArray *policies = [NSMutableArray array];
if (self.validatesDomainName) {
//需要验证域名的情况
//返回用于验证SSL证书链的policy对象,当第一个参数传入的是true的时候会创建一个SSL服务端证书。
[policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)];
} else {
//不需要验证域名的情况
//创建一个默认的X.509 policy
[policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()];
}

//设置验证serverTrust所需要的policies
SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies);

//这里应该是进行系统认证[不确定]
if (self.SSLPinningMode == AFSSLPinningModeNone) {
//如果SSLPinningMode为AFSSLPinningModeNone如果允许无效的证书或者调用AFServerTrustIsValid返回YES的时候返回YES 表示认证通过
return self.allowInvalidCertificates || AFServerTrustIsValid(serverTrust);
} else if (!AFServerTrustIsValid(serverTrust) && !self.allowInvalidCertificates) {
/*模式不是AFSSLPinningModeNone 不允许无效证书的情况下如果AFServerTrustIsValid返回NO 则返回NO,表示认证不通过*/
return NO;
}

switch (self.SSLPinningMode) {
case AFSSLPinningModeNone:
default:
return NO;
case AFSSLPinningModeCertificate: {
NSMutableArray *pinnedCertificates = [NSMutableArray array];
//使用self.pinnedCertificates通过SecCertificateCreateWithData方法创建证书数据
for (NSData *certificateData in self.pinnedCertificates) {
[pinnedCertificates addObject:(__bridge_transfer id)SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData)];
}
//使用 SecTrustSetAnchorCertificates 为serverTrust设置证书
SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCertificates);
//使用证书认证
if (!AFServerTrustIsValid(serverTrust)) {
return NO;
}
//使用 AFCertificateTrustChainForServerTrust 获取serverTrust中的全部 DER 表示的证书
NSArray *serverCertificates = AFCertificateTrustChainForServerTrust(serverTrust);
//如果 pinnedCertificates 中有相同的证书,就会返回 YES
for (NSData *trustChainCertificate in [serverCertificates reverseObjectEnumerator]) {
if ([self.pinnedCertificates containsObject:trustChainCertificate]) {
return YES;
}
}
return NO;
}
case AFSSLPinningModePublicKey: {
NSUInteger trustedPublicKeyCount = 0;
//从serverTrust中获取公钥
NSArray *publicKeys = AFPublicKeyTrustChainForServerTrust(serverTrust);

for (id trustChainPublicKey in publicKeys) {
//pinnedPublicKeys 中的公钥包含serverTrust中的公钥的时候认证通过
for (id pinnedPublicKey in self.pinnedPublicKeys) {
if (AFSecKeyIsEqualToKey((__bridge SecKeyRef)trustChainPublicKey, (__bridge SecKeyRef)pinnedPublicKey)) {
trustedPublicKeyCount += 1;
}
}
}
return trustedPublicKeyCount > 0;
}
}
return NO;
}

那如果我们需要添加证书文件要怎么实现呢?下面是一个例子供大家参考

- (void)setSecurityPolicyWithCerPath:(NSString *)cerPath validatesDomainName:(BOOL)validatesDomainName {
NSData *cerData = [NSData dataWithContentsOfFile:cerPath];
// 使用证书验证模式
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
// 如果需要验证自建证书(无效证书),需要设置为YES
securityPolicy.allowInvalidCertificates = YES;
// 是否需要验证域名,默认为YES;
securityPolicy.validatesDomainName = validatesDomainName;
securityPolicy.pinnedCertificates = [[NSSet alloc] initWithObjects:cerData, nil];
[self setSecurityPolicy:securityPolicy];
}
  • 通过AFNetworkReachabilityManager 监控网络状态

一般我们应用都会有个应用场景:在网络断开或者异常的时候,显示重试页面,当网络恢复的时候自动调用数据获取接口,恢复正常界面。这个功能就可以通过AFNetworkReachabilityManager来实现了。

  • AFNetworkReachabilityManager实例的创建:

+ (instancetype)sharedManager {
static AFNetworkReachabilityManager *_sharedManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedManager = [self manager];
});

return _sharedManager;
}

不解释,嗯!

- (void)startMonitoring {

//开始监听之前先取消之前的监听,重新开始网络监听
[self stopMonitoring];

//如果没有设置networkReachability 直接返回
if (!self.networkReachability) {
return;
}

//网络状态变更的时候传递出去的Block
__weak __typeof(self)weakSelf = self;
AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
strongSelf.networkReachabilityStatus = status;
if (strongSelf.networkReachabilityStatusBlock) {
strongSelf.networkReachabilityStatusBlock(status);
}
};

//创建SCNetworkReachabilityContext,这里最关键是callback,而AFNetworkReachabilityRetainCallback,AFNetworkReachabilityReleaseCallback是用于管理AFNetworkReachabilityStatusBlock内存的回调。
SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL};
SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context);

//在 Main 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);
}
});
}

通过上述设置后,每次网络状态改变就会调用 AFNetworkReachabilityCallback 函数,在这里会调用AFPostReachabilityStatusChange抛出状态改变的通知:

static void AFNetworkReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkReachabilityFlags flags, void *info) {
AFPostReachabilityStatusChange(flags, (__bridge AFNetworkReachabilityStatusBlock)info);
}

我们知道状态抛出是通过开启监听之前设置的AFNetworkReachabilityStatusBlock 类型的callback block 传递到业务层的。

static void AFPostReachabilityStatusChange(SCNetworkReachabilityFlags flags, AFNetworkReachabilityStatusBlock block) {
AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags);
dispatch_async(dispatch_get_main_queue(), ^{
if (block) {
block(status);
}
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
NSDictionary *userInfo = @{ AFNetworkingReachabilityNotificationStatusItem: @(status) };
[notificationCenter postNotificationName:AFNetworkingReachabilityDidChangeNotification object:nil userInfo:userInfo];
});
}

AFPostReachabilityStatusChange会先通过AFNetworkReachabilityStatusForFlags从SCNetworkReachabilityFlags中提取对应的标志生成AFNetworkReachabilityStatus对象,在使用AFNetworkReachabilityStatusBlock传递出去,同时通过AFNetworkingReachabilityDidChangeNotification广播通知其他部件。

上述的flag是一个kSCNetworkReachabilityFlagsReachable类型,不同的位代表不同的状态。

static AFNetworkReachabilityStatus AFNetworkReachabilityStatusForFlags(SCNetworkReachabilityFlags flags) {
BOOL isReachable = ((flags & kSCNetworkReachabilityFlagsReachable) != 0);
BOOL needsConnection = ((flags & kSCNetworkReachabilityFlagsConnectionRequired) != 0);
BOOL canConnectionAutomatically = (((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) || ((flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0));
BOOL canConnectWithoutUserInteraction = (canConnectionAutomatically && (flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0);
BOOL isNetworkReachable = (isReachable && (!needsConnection || canConnectWithoutUserInteraction));

AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusUnknown;
if (isNetworkReachable == NO) {
status = AFNetworkReachabilityStatusNotReachable;
}
#if TARGET_OS_IPHONE
else if ((flags & kSCNetworkReachabilityFlagsIsWWAN) != 0) {
status = AFNetworkReachabilityStatusReachableViaWWAN;
}
#endif
else {
status = AFNetworkReachabilityStatusReachableViaWiFi;
}

return status;
}

好了好了,说好不熬夜的又2点了,不早了就这样吧。……(^_^)v

Contents
  1. 1. 开源库信息
  2. 2. AFNetWorking 源码解析
    1. 2.1. AFNetWorking 组成
    2. 2.2. AFNetWorking 框架总览