美文网首页iOS
AFNetworking 的核心 AFURLSessionMan

AFNetworking 的核心 AFURLSessionMan

作者: 果哥爸 | 来源:发表于2017-09-12 19:56 被阅读15次

    主要参考:
    AFNetworking 的核心 AFURLSessionManager

    AFURLSessionManagerAFNetworking的核心。

    1. 负责创建和管理 NSURLSession
    2. 管理 NSURLSessionTask
    3. 实现 NSURLSessionDelegate 等协议中的代理方法
    4. 使用AFURLSessionManagerTaskDelegate 管理进度
    5. 使用_AFURLSessionTaskSwizzling调剂方法。
    6. 引入AFSecurityPolicy 保证请求的安全
    7. 引入AFNetworkReachabilityManager监控网络状态

    我们会在这里着重介绍上面七个功能中的五个,分析它是如何包装NSURLSession以及众多代理方法。

    一. 创建和管理NSURLSession

    在使用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];
    
        self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
    
        self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];
    
        self.lock = [[NSLock alloc] init];
        self.lock.name = AFURLSessionManagerLockName;
    
        #1: 为已有的 task 设置代理, 略
    
        return self;
    }
    

    在初始化方法中,需要完成初始化自己持有的实例:

    • 初始化会话配置(NSURLSessionConfiguration),默认为defaultSessionConfiguration

    • 初始化会话(session),并设置会话的代理以及代理队列

    • 初始化管理响应序列化(AFJSONResponseSerializer),安全认证(AFSecurityPolicy)以及监控网络状态(AFNetworkReachabilityManager)的实例。

    • 初始化保存data task的字典(mutableTaskDelegateKeyedByTaskIdentifier)

    二. 管理 NSURLSessionTask

    接下来,在获得了AFURLSessionManager的实例之后,我们可以通过以下方法创建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;
    
    - (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;
    
    ...
    
    - (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request
                                             progress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
                                          destination:(nullable NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
                                    completionHandler:(nullable void (^)(NSURLResponse *response, NSURL * _Nullable filePath, NSError * _Nullable error))completionHandler;
    
    ...
    

    这里省略了一些返回NSURLSesstionTask 的方法,因为这些接口形式都是差不多,所以我们将以- [AFURLSessionManager dataTaskWithRequest: uploadProgress: downloadProgress:completionHandler:]方法实例,分析它是如何实例化并返回一个NSURLSestionTask的实例的。

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

    url_session_manager_create_task_safely的调用是因为苹果框架中的一个 bug #2093

    static void url_session_manager_create_task_safely(dispatch_block_t block) {
        if (NSFoundationVersionNumber <</span> NSFoundationVersionNumber_With_Fixed_5871104061079552_bug) {
        // Fix of bug
        // Open Radar:[http://openradar.appspot.com/radar?id=5871104061079552](http://openradar.appspot.com/radar?id=5871104061079552) (status: Fixed in iOS8)
        // Issue about:[https://github.com/AFNetworking/AFNetworking/issues/2093](https://github.com/AFNetworking/AFNetworking/issues/2093)
    
    //理解下,第一为什么用sync,因为是想要主线程等在这,等执行完,在返回,因为必须执行完dataTask才有数据,传值才有意义。 
    
    //第二,为什么要用串行队列,因为这块是为了防止ios8以下内部的dataTaskWithRequest是并发创建的, 
    
    //这样会导致taskIdentifiers这个属性值不唯一,因为后续要用taskIdentifiers来作为Key对应delegate。
    
           dispatch_sync(url_session_manager_creation_queue(), block);
    } else {
            block();
        }
    }
    
    • 调用- [NSURLSession dataTaskWithRequest:]方法传入NSURLRequest

    • 调用 - [AFURLSessionManager addDelegateForDataTask:uploadProgress:downloadProgress:completionHandler:] 方法返回一个 AFURLSessionManagerTaskDelegate对象

    • completionHandler uploadProgressBlockdownloadProgressBlock传入该对象并在相应事件发生时进行回调

    - (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
    {
        
    #1: 检查参数, 略
    
        [self.lock lock];
        self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
        [delegate setupProgressForTask:task];
        [self addNotificationObserverForTask:task];
        [self.lock unlock];
    }
    

    正如上面所提到的,AFURLSessionManager就是通过字典 mutableTaskDelegatesKeyedByTaskIdentifier 来存储管理每一个NSURLSessionTask, 它以 taskIdentifier为键存储task

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

    同时调用 - setupProgressForTask:, 我们会在下面具体介绍这个方法。

    三. 实现 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;
    ...
    

    它为所有的代理协议都提供了对应的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是如何对进度进行跟踪的:

    - (void)setupProgressForTask:(NSURLSessionTask *)task {
    
        #1:设置在上传进度或者下载进度状态改变时的回调
    
        #2:KVO
    
    }
    

    该方法的实现有两个部分:

    • 对代理持有的两个属性uploadProgressdownloadProgress 设置回调。

       __weak __typeof__(task) weakTask = task;
      
       self.uploadProgress.totalUnitCount = task.countOfBytesExpectedToSend;
      [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];
          }];
       }
      

    这里只有对uploadProgerss设置回调的代码,设置downloadPregress回调原理相同主要目的是在对应NSProgress的状态改变时,调用resume,suspend等方法改变task的状态。

    • taskNSProgress属性进行键值观测:

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

    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]]) {
            if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesReceived))]) {
                self.downloadProgress.completedUnitCount = [change[@"new"] longLongValue];
            } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesExpectedToReceive))]) {
                self.downloadProgress.totalUnitCount = [change[@"new"] longLongValue];
            } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesSent))]) {
                self.uploadProgress.completedUnitCount = [change[@"new"] longLongValue];
            } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesExpectedToSend))]) {
                self.uploadProgress.totalUnitCount = [change[@"new"] 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.uploadPregressBlock(object).

    代理方法URLSession:task:didCompleteWithError:

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

    调用传入的completionHander block
    发出 AFNetworkingTaskDidCompleteNotification 通知

    - (void)URLSession:(__unused NSURLSession *)session
              task:(NSURLSessionTask *)task
    didCompleteWithError:(NSError *)error
    {
        #1:获取数据, 存储 `responseSerializer` 和 `downloadFileURL`
    
        if (error) {
            #2:在存在错误时调用 `completionHandler`
        } else {
            #3:调用 `completionHandler`
        }
    }
    

    这是整个代理方法的骨架,先看下最简单的第一部分代码:

    __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 (self.downloadFileURL) {
       userInfo[AFNetworkingTaskDidCompleteAssetPathKey] = self.downloadFileURL;
    } else if (data) {
       userInfo[AFNetworkingTaskDidCompleteResponseDataKey] = data;
    }
    

    这部分代码从mutableData中取出了数据,设置了userInfo

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

    如果当前manager持有completionGroup或者completionQueue就使用它们。否则会创建一个dispatch_group_t并在主线程中调用completionHandler并发送通知(在主线程中)。

    如果在执行当前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]; 
            });
         });
    });
    

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

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

    - (void)URLSession:(__unused NSURLSession *)session
          dataTask:(__unused NSURLSessionDataTask *)dataTask
    didReceiveData:(NSData *)data
    {
        [self.mutableData appendData:data];
    }
    
    - (void)URLSession:(NSURLSession *)session
      downloadTask:(NSURLSessionDownloadTask *)downloadTask
    didFinishDownloadingToURL:(NSURL *)location
    {
        NSError *fileManagerError = nil;
        self.downloadFileURL = nil;
    
        if (self.downloadTaskDidFinishDownloading) {
            self.downloadFileURL = self.downloadTaskDidFinishDownloading(session, downloadTask, location);
            if (self.downloadFileURL) {
                [[NSFileManager defaultManager] moveItemAtURL:location toURL:self.downloadFileURL error:&fileManagerError];
    
                if (fileManagerError) {
                    [[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDownloadTaskDidFailToMoveFileNotification object:downloadTask userInfo:fileManagerError.userInfo];
                }
            }
        }
    }
    

    五. 使用_AFURLSessionTaskSwizzling调剂方法

    _AFURLSessionTaskSwizzing 的唯一功能就是修改NSURLSessionTaskresumesuspend方法,使用下面的方法替换原有的实现

    - (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方法中进行的

    load 方法只会在整个文件被引入是调用一次

    + (void)load {
        if (NSClassFromString(@"NSURLSessionTask")) {
            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];
        }
    }
    
    • 首先用 NSClassFromString(@"NSURLSessionTask") 判断当前部署的iOS版本是否含有类NSURLSessionTask

    • 因为iOS7iOS 8上对于NSURLSessionTask的实现不同,所以会通过- [NSURLSession dataTaskWithURL:]方法返回一个 NSURLSessionTask 实例。

    • 取得当前类_AFURLSessionTaskSwizzing中的实现af_resume

    • 如果当前类 currentClassresume 方法,执行第五步,否则执行第六步。

    • 使用 swizzleResumeAndSuspendMethodForClass: 调剂该类的 resumesuspend 方法。

    • currentClass = [currentClass superclass]

    六. 引入 AFSecurityPolicy 保证请求的安全

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

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

    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. 持有一个字典mutableTaskDelegatesKeyByTaskIdentifier管理这些data task 实例。

    4. 引入 AFURLSessionManagerTaskDelegate 来对传入的uploadProgressBlock downloadProgressBlock、completionHandler 在合适的时间进行调用

    5. 实现了全部的代理方法来提供block接口

    6. 通过方法调剂在data task 状态改变时,发出通知。

    相关文章

      网友评论

        本文标题:AFNetworking 的核心 AFURLSessionMan

        本文链接:https://www.haomeiwen.com/subject/skbujxtx.html