AFNetworking3 源码分析

声明:以下是对所看源码和相关资料的整理

框架组成

AFNetworking作为开发中使用最多的第三方网络库,功能完善,代码结构简洁、清晰易懂,非常值得仔细研究。先看一下结构目录

目录结构图

除去Support Files和AFNetworking.h,分为如下5个功能模块:

  • 网络通信模块(NSURLSession)
  • 网络状态监听模块(Reachability)
  • 网络通信安全策略模块(Security)
  • 网络通信信息序列化/反序列化模块(Serialization)
  • 对于iOS UIKit库的扩展(UIKit)

AFURLSessionManager是AFNetworking的核心类,AFHTTPSessionManager继承于AFURLSessionManager, 针对HTTP协议传输做了特化。AFURLResponseSerialization, AFSecurityPolicy, AFNetworkReachabilityManager作为AFURLSessionManager的属性,提供相应的功能。

还有一个单独的UIKit包提供了对iOS UIKit类库的扩展与工具类。

网络通信核心AFURLSessionManager

AFNetworking是基于NSURLSession实现的。NSURLSession的使用方式如下:

  1. 创建NSURLSessionConfig对象
  2. 用之前创建的NSURLSessionConfig对象创建配置NSURLSession对象。
  3. 用NSURLSession对象创建对应的task对象,并用resume方法执行之。
  4. 用delegate方法或completion block 响应网络事件及数据。

对应于每次网络会话,对应一个NSURLSession对象,而每个会话,可以生成若干task对象用于数据的交互。

在AFNetworking中, AFURLSessionManager封装并提供了上述网络交互功能。

AFURLSessionManager.h的属性

  • AFURLSessionManager所管理的Session对象

@property (readonly, nonatomic, strong) NSURLSession *session;

  • delegate所返回的NSOperationQueue

@property (readonly, nonatomic, strong) NSOperationQueue *operationQueue;

  • 解析网络返回数据的对象(遵循AFURLResponseSerialization协议)

@property (nonatomic, strong) id <AFURLResponseSerialization> responseSerializer;

  • 用于处理网络连接安全处理策略的AFSecurityPolicy对象

@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;

  • 用于检测网络状态的AFNetworkReachabilityManager对象

@property (readwrite, nonatomic, strong) AFNetworkReachabilityManager *reachabilityManager;

  • 当前的Session对象的tasks

@property (readonly, nonatomic, strong) NSArray <NSURLSessionTask *> *tasks;

  • 当前的Session对象的dataTasks

@property (readonly, nonatomic, strong) NSArray <NSURLSessionDataTask *> *dataTasks;

  • 当前的Session对象的uploadTasks

@property (readonly, nonatomic, strong) NSArray <NSURLSessionUploadTask *> *uploadTasks;

  • 当前的Session对象的downloadTasks

@property (readonly, nonatomic, strong) NSArray <NSURLSessionDownloadTask *> *downloadTasks;

  • 设置Call back队列,默认为main block

@property (nonatomic, strong, nullable) dispatch_queue_t completionQueue;

@property (nonatomic, strong, nullable) dispatch_group_t completionGroup;

结合上面所说再看这些属性的功能都很清楚了。

AFURLSessionManager.m

.m代码中还有AFURLSessionManagerTaskDelegate、_AFURLSessionTaskSwizzling两个类,功能如下

  • AFURLSessionManagerTaskDelegate管理进度
  • _AFURLSessionTaskSwizzling 调剂方法

在使用 AFURLSessionManager 时,第一件要做的事情一定是初始化:

- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
    self = [super init];
    if (!self) {
        return nil;
    }

    if (!configuration) {
        configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    }

    self.sessionConfiguration = configuration;

    self.operationQueue = [[NSOperationQueue alloc] init];
    self.operationQueue.maxConcurrentOperationCount = 1;

    self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];

    self.responseSerializer = [AFJSONResponseSerializer serializer];

    self.securityPolicy = [AFSecurityPolicy defaultPolicy];

#if !TARGET_OS_WATCH
    self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
#endif

    self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];

    self.lock = [[NSLock alloc] init];
    self.lock.name = AFURLSessionManagerLockName;

    //为已有的 task 设置代理
    [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
        for (NSURLSessionDataTask *task in dataTasks) {
            [self addDelegateForDataTask:task uploadProgress:nil downloadProgress:nil completionHandler:nil];
        }

        for (NSURLSessionUploadTask *uploadTask in uploadTasks) {
            [self addDelegateForUploadTask:uploadTask progress:nil completionHandler:nil];
        }

        for (NSURLSessionDownloadTask *downloadTask in downloadTasks) {
            [self addDelegateForDownloadTask:downloadTask progress:nil destination:nil completionHandler:nil];
        }
    }];

    return self;
}

其中mutableTaskDelegatesKeyedByTaskIdentifier是存储task与AFURLSessionManagerTaskDelegate的词典,在AFNetworking中,每一个task都会被匹配一个AFURLSessionManagerTaskDelegate来做task的delegate的事件处理

self.lock用于确保mutableTaskDelegatesKeyedByTaskIdentifier在多线程访问时的线程安全

管理 NSURLSessionTask

在初始化AFURLSessionManager之后,我们可以通过以下方法创建 NSURLSessionDataTask 的实例:

- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
                            completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject,  NSError * _Nullable error))completionHandler;

- (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;

- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
                                         fromFile:(NSURL *)fileURL
                                         progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
                                completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError  * _Nullable error))completionHandler;

- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
                                         fromData:(nullable NSData *)bodyData
                                         progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
                                completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;

- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request
                                                 progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
                                        completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;

这些接口的实现都类似,以- [AFURLSessionManager dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler:] 方法为例,分析它是如何实例化并返回一个 NSURLSessionTask 的实例的:

- (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(^{
        dataTask = [self.session dataTaskWithRequest:request];
    });

    [self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];

    return dataTask;
}

上述方法完成了两件事情:

  1. 生成一个data task对象,并返回。这里为了避免iOS 8.0以下版本中偶发的taskIdentifiers不唯一的bug,调用了url_session_manager_create_task_safely函数,可能是因为iOS 8.0以下版本中会并发地创建多个task对象,而同步有没有做好,导致taskIdentifiers不唯一…
  2. 为该data task对象生成一个匹配的AFURLSessionManagerTaskDelegate对象并关联,这里说明以下[addDelegateForDataTask:uploadProgress: downloadProgress: completionHandler:]方法。
- (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 *delegate = [[AFURLSessionManagerTaskDelegate alloc] init];
    delegate.manager = self;
    delegate.completionHandler = completionHandler;

    dataTask.taskDescription = self.taskDescriptionForSessionTasks;
    [self setDelegate:delegate forTask:dataTask];

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

在这个方法中同时调用了另一个方法 - [AFURLSessionManager setDelegate:forTask:] 来设置代理

- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
            forTask:(NSURLSessionTask *)task
{
    NSParameterAssert(task);
    NSParameterAssert(delegate);

    [self.lock lock];
    self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
    [delegate setupProgressForTask:task];
    [self addNotificationObserverForTask:task];
    [self.lock unlock];
}

该方法使用 NSLock 来保证不同线程使用 mutableTaskDelegatesKeyedByTaskIdentifier 时,不会出现 线程竞争的问题。

看了这两个方法,AFURLSessionManager通过字典 mutableTaskDelegatesKeyedByTaskIdentifier 来存储并管理每一个 NSURLSessionTask ,它以 taskIdentifier 为键存储 task。NSURLSessionTask的Delegate返回结果都在AFURLSessionManagerTaskDelegate中处理,再由AFURLSessionManagerTaskDelegate传给AFURLSessionManager。

实现 NSURLSessionDelegate 等协议中的代理方法

在 AFURLSessionManager 的头文件中可以看到,它遵循了多个协议,其中包括:

  • NSURLSessionDelegate
  • NSURLSessionTaskDelegate
  • NSURLSessionDataDelegate
  • NSURLSessionDownloadDelegate

它在初始化方法 - [AFURLSessionManager initWithSessionConfiguration:] 将NSURLSession的代理指向 self,然后实现这些方法,提供更简洁的block的接口:

- (void)setSessionDidBecomeInvalidBlock:(nullable void (^)(NSURLSession *session, NSError *error))block;
- (void)setSessionDidReceiveAuthenticationChallengeBlock:(nullable NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * _Nullable __autoreleasing * _Nullable credential))block;
- (void)setTaskNeedNewBodyStreamBlock:(nullable NSInputStream * (^)(NSURLSession *session, NSURLSessionTask *task))block;
...

它为所有的代理协议都提供了对应的block接口,方法实现的思路都是相似的,我们以 - [AFNRLSessionManager setSessionDidBecomeInvalidBlock:]为例。

首先调用 setter 方法,将 block 存入 sessionDidBecomeInvalid 属性中:

- (void)setSessionDidBecomeInvalidBlock:(void (^)(NSURLSession *session, NSError *error))block {
    self.sessionDidBecomeInvalid = block;
}

当代理方法调用时,如果存在对应的 block,会执行对应的 block:

- (void)URLSession:(NSURLSession *)session
didBecomeInvalidWithError:(NSError *)error  
{
    if (self.sessionDidBecomeInvalid) {
        self.sessionDidBecomeInvalid(session, error);
    }

    [[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDidInvalidateNotification object:session];
}

其他相似的接口实现也都差不多,直接跳过。

使用 AFURLSessionManagerTaskDelegate 管理进度

AFURLSessionManagerTaskDelegate主要为task提供进度管理功能,并在task结束时回调,也就是调用在- [AFURLSessionManager dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler:]等方法中传入的completionHandler 。

AFURLSessionManagerTaskDelegate 对进度进行跟踪,以uploadProgress 为例:

- (void)setupProgressForTask:(NSURLSessionTask *)task {
    __weak __typeof__(task) weakTask = task;

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

    [task addObserver:self
           forKeyPath:NSStringFromSelector(@selector(countOfBytesReceived))
              options:NSKeyValueObservingOptionNew
              context:NULL];
    [task addObserver:self
           forKeyPath:NSStringFromSelector(@selector(countOfBytesExpectedToReceive))
              options:NSKeyValueObservingOptionNew
              context:NULL];

    [task addObserver:self
           forKeyPath:NSStringFromSelector(@selector(countOfBytesSent))
              options:NSKeyValueObservingOptionNew
              context:NULL];
    [task addObserver:self
           forKeyPath:NSStringFromSelector(@selector(countOfBytesExpectedToSend))
              options:NSKeyValueObservingOptionNew
              context:NULL];

    [self.downloadProgress addObserver:self
                            forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
                               options:NSKeyValueObservingOptionNew
                               context:NULL];
    [self.uploadProgress addObserver:self
                          forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
                             options:NSKeyValueObservingOptionNew
                             context:NULL];
}

前半部分对应 NSProgress 的状态改变时,调用 resume suspend 等方法改变 task 的状态。后半部分对task 和 NSProgress 属性进行键值观测。

在 observeValueForKeypath:ofObject:change:context: 方法中改变进度,并调用 block

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
    if ([object isKindOfClass:[NSURLSessionTask class]] || [object isKindOfClass:[NSURLSessionDownloadTask class]]) {
        if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesReceived))]) {
            self.downloadProgress.completedUnitCount = [change[NSKeyValueChangeNewKey] longLongValue];
        } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesExpectedToReceive))]) {
            self.downloadProgress.totalUnitCount = [change[NSKeyValueChangeNewKey] longLongValue];
        } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesSent))]) {
            self.uploadProgress.completedUnitCount = [change[NSKeyValueChangeNewKey] longLongValue];
        } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesExpectedToSend))]) {
            self.uploadProgress.totalUnitCount = [change[NSKeyValueChangeNewKey] longLongValue];
        }
    }
    else if ([object isEqual:self.downloadProgress]) {
        if (self.downloadProgressBlock) {
            self.downloadProgressBlock(object);
        }
    }
    else if ([object isEqual:self.uploadProgress]) {
        if (self.uploadProgressBlock) {
            self.uploadProgressBlock(object);
        }
    }
}

对象的某些属性改变时更新 NSProgress 对象或使用 block 传递 NSProgress 对象 self.uploadProgressBlock(object)

代理方法 URLSession:task:didCompleteWithError:

在每一个NSURLSessionTask结束时,都会在代理方法 URLSession:task:didCompleteWithError:中:

  1. 调用传入的completionHander
  2. 发出AFNetworkingTaskDidCompleteNotification通知
- (void)URLSession:(__unused NSURLSession *)session
              task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
    __strong AFURLSessionManager *manager = self.manager;

    __block id responseObject = nil;

    __block NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
    
   //从 mutableData 中取出了数据,设置了 userInfo
    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 (self.downloadFileURL) {
        userInfo[AFNetworkingTaskDidCompleteAssetPathKey] = self.downloadFileURL;
    } else if (data) {
        userInfo[AFNetworkingTaskDidCompleteResponseDataKey] = data;
    }

    if (error) {
        userInfo[AFNetworkingTaskDidCompleteErrorKey] = error;
        
        //如果当前 manager 持有 completionGroup 或者 completionQueue 就使用它们。否则会创建一个 dispatch_group_t 并在主线程中调用 completionHandler 并发送通知(在主线程中)。
        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 {
        //如果在执行当前 task 时没有遇到错误,那么先 对数据进行序列化 ,然后同样调用 block 并发送通知。
        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];
                });
            });
        });
    }
#pragma clang diagnostic pop
}

代理方法 URLSession:dataTask:didReceiveData: 和 - URLSession:downloadTask:didFinishDownloadingToURL:

这两个代理方法分别会在收到数据或者完成下载对应文件时调用,作用分别是为 mutableData 追加数据和处理下载的文件:

_AFURLSessionTaskSwizzling 调剂方法

_AFURLSessionTaskSwizzling 的唯一功能就是修改 NSURLSessionTask 的 resume 和 suspend 方法,使用下面的方法替换原有的实现

- (void)af_resume {
    NSAssert([self respondsToSelector:@selector(state)], @"Does not respond to state");
    NSURLSessionTaskState state = [self state];
    [self af_resume];
    
    if (state != NSURLSessionTaskStateRunning) {
        [[NSNotificationCenter defaultCenter] postNotificationName:AFNSURLSessionTaskDidResumeNotification object:self];
    }
}

- (void)af_suspend {
    NSAssert([self respondsToSelector:@selector(state)], @"Does not respond to state");
    NSURLSessionTaskState state = [self state];
    [self af_suspend];
    
    if (state != NSURLSessionTaskStateSuspended) {
        [[NSNotificationCenter defaultCenter] postNotificationName:AFNSURLSessionTaskDidSuspendNotification object:self];
    }
}

这样做的目的是为了在方法 resume 或者 suspend 被调用时发出通知。

具体方法调剂的过程是在 + load 方法中进行的

+ (void)load {
        NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
        NSURLSession * session = [NSURLSession sessionWithConfiguration:configuration];
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnonnull"
        NSURLSessionDataTask *localDataTask = [session dataTaskWithURL:nil];
#pragma clang diagnostic pop
        IMP originalAFResumeIMP = method_getImplementation(class_getInstanceMethod([self class], @selector(af_resume)));
        Class currentClass = [localDataTask class];
        
        while (class_getInstanceMethod(currentClass, @selector(resume))) {
            Class superClass = [currentClass superclass];
            IMP classResumeIMP = method_getImplementation(class_getInstanceMethod(currentClass, @selector(resume)));
            IMP superclassResumeIMP = method_getImplementation(class_getInstanceMethod(superClass, @selector(resume)));
            if (classResumeIMP != superclassResumeIMP &&
                originalAFResumeIMP != classResumeIMP) {
                [self swizzleResumeAndSuspendMethodForClass:currentClass];
            }
            currentClass = [currentClass superclass];
        }
        
        [localDataTask cancel];
        [session finishTasksAndInvalidate];
    }
}
  1. 首先用 NSClassFromString(@"NSURLSessionTask") 判断当前部署的 iOS 版本是否含有类 NSURLSessionTask
    2.因为 iOS7 和 iOS8 上对于 NSURLSessionTask 的实现不同,所以会通过 - [NSURLSession dataTaskWithURL:] 方法返回一个 NSURLSessionTask 实例
  2. 取得当前类 _AFURLSessionTaskSwizzling 中的实现 af_resume
  3. 判断当前类 currentClass 有 resume 方法
  4. 使用swizzleResumeAndSuspendMethodForClass: 调剂该类的 resume 和 suspend 方法
  5. currentClass = [currentClass superclass]

这里复杂的实现是为了解决 bug #2702

引入 AFSecurityPolicy 保证请求的安全

AFSecurityPolicy 是 AFNetworking 用来保证 HTTP 请求安全的类,它被 AFURLSessionManager 持有,如果你在 AFURLSessionManager 的实现文件中搜索 self.securityPolicy ,你只会得到三条结果:

  1. 初始化 self.securityPolicy = [AFSecurityPolicy defaultPolicy]
  2. 收到连接层的验证请求时
  3. 任务接收到验证请求时

在 API 调用上,后两者都调用了 - [AFSecurityPolicy evaluateServerTrust:forDomain:] 方法来判断 当前服务器是否被信任 ,我们会在接下来的文章中具体介绍这个方法的实现的作用。

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

    if (self.taskDidReceiveAuthenticationChallenge) {
        disposition = self.taskDidReceiveAuthenticationChallenge(session, task, challenge, &credential);
    } else {
        if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
            if ([self.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
                disposition = NSURLSessionAuthChallengeUseCredential;
                credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
            } else {
                disposition = NSURLSessionAuthChallengeRejectProtectionSpace;
            }
        } else {
            disposition = NSURLSessionAuthChallengePerformDefaultHandling;
        }
    }

    if (completionHandler) {
        completionHandler(disposition, credential);
    }
}

如果没有传入 taskDidReceiveAuthenticationChallenge block,只有在上述方法返回 YES 时,才会获得认证凭证 credential 。

引入 AFNetworkReachabilityManager 监控网络状态

与 AFSecurityPolicy 相同, AFURLSessionManager 对网络状态的监控是由 AFNetworkReachabilityManager 来负责的,它仅仅是持有一个 AFNetworkReachabilityManager 的对象。

真正需要判断网络状态时,仍然需要开发者调用对应的API获取网络状态。

小结

  1. AFURLSessionManager是对NSURLSession的封装
  2. 它通过 - [AFURLSessionManager dataTaskWithRequest:completionHandler:]等接口创建 NSURLSessionDataTask的实例
  3. 持有一个字典mutableTaskDelegatesKeyedByTaskIdentifier 管理这些dataTask实例
  4. 引入AFURLSessionManagerTaskDelegate来对传入的 uploadProgressBlock和downloadProgressBlock的completionHandler在合适的时间进行调用
  5. 实现了全部的代理方法来提供block接口
  6. 通过方法调剂在dataTask状态改变时,发出通知
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容