AFNetWorking源码之AFURLSessionManager

1 概述

AFNetWorking基本上是所有iOS项目的标配。现在升级带最新版的3.X了。得益于苹果从NSURLConnection升级到NSURLSession,AFN也实现了api的简化,同时功能却一点没少。我们来看一下AFN3.X的目录结构:

  • AFNetWorking 这个文件是一个头文件。啥也没做,就是引入了其他文件方便使用。
  • AFURLSessionManager 这个文件是核心类,基本上通过它来实现了大部分核心功能。负责请求的建立、管理、销毁、安全、请求重定向、请求重启等各种功能。他主要实现了NSURLSessionNSRULSessionTask的封装。
  • AFHTTPSessionManager 这个文件是AFURLSessionManager的子类。主要实现了对HTTP请求的优化。
  • AFURLRequestSerialization 这个主要用于请求头的编码解码、序列化、优化处理、简化请求拼接过程等。
  • AFURLResponseSerialization 这个主要用于网络返回数据的序列化、编码解码、序列化、数据处理等。
  • AFSecurityPolicy 这个主要用于请求的认证功能。比如https的认证模式等。
  • AFNetworkReachabilityManager 这个主要用于监听网络请求状态变化功能。

首先说明,看AFN源码之前一定要搞清楚NSURLSession系列的api,这样能让你事半功倍,具体可以看AFNetWorking源码之NSRULSession系列概述。在这篇文章里,我们主要讲解AFURLSessionManager的实现原理和封装过程。首先我们通过一个简单的网络请求看一下他的基本用法(大部分都是非必须的,这里为了掩饰写出来):

- (IBAction)clickButton:(id)sender {
    //通过默认配置初始化Session
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
    //设置网络请求序列化对象
    AFHTTPRequestSerializer *requestSerializer = [AFHTTPRequestSerializer serializer];
    [requestSerializer setValue:@"test" forHTTPHeaderField:@"requestHeader"];
    requestSerializer.timeoutInterval = 60;
    requestSerializer.stringEncoding = NSUTF8StringEncoding;
    //设置返回数据序列化对象
    AFHTTPResponseSerializer *responseSerializer = [AFHTTPResponseSerializer serializer];
    manager.responseSerializer = responseSerializer;
    //网络请求安全策略
    if (true) {
        AFSecurityPolicy *securityPolicy;
        securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey];
        securityPolicy.allowInvalidCertificates = false;
        securityPolicy.validatesDomainName = YES;
        manager.securityPolicy = securityPolicy;
    } else {
        manager.securityPolicy.allowInvalidCertificates = true;
        manager.securityPolicy.validatesDomainName = false;
    }
    //是否允许请求重定向
    if (true) {
        [manager setTaskWillPerformHTTPRedirectionBlock:^NSURLRequest *(NSURLSession *session, NSURLSessionTask *task, NSURLResponse *response, NSURLRequest *request) {
            if (response) {
                return nil;
            }
            return request;
        }];
    }
    //监听网络状态
    [manager.reachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
        NSLog(@"%ld",(long)status);
    }];
    [manager.reachabilityManager startMonitoring];
    
    NSURL *URL = [NSURL URLWithString:bigPic];
    NSURLRequest *request = [NSURLRequest requestWithURL:URL];
    NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:^(NSProgress *downloadProgress){
        NSLog(@"下载进度:%lld",downloadProgress.completedUnitCount);
    } destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
        NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
        NSURL *fileURL = [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]];
        NSLog(@"fileURL:%@",[fileURL absoluteString]);
        return fileURL;
    } completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
        self.imageView.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:filePath]];
        NSLog(@"File downloaded to: %@", filePath);
    }];
    [downloadTask resume];
}

通过这个请求,我们发现AFURLSessionManager要负责以下几块功能。

  • 初始化和管理NSURLSession,通过它来建立和管理各种Task。
  • 初始化和管理NSRULSessionTask,通过不同task来发送不同请求。
  • 管理各种认证功能、安全功能、请求重定向、数据处理。
  • 管理和组织每个task的各种状态管理和通知管理。不同task的回调处理。
  • 帮我们管理和处理了NSRULSession系列api的各种代理方法。简化了我们的处理。

2 AFURLSessionManager的声明分析

AFURLSessionManager根据一个指定的NSURLSessionConfiguration创建和管理一个NSURLSession对象。并且这个对象实现了<NSURLSessionTaskDelegate>, <NSURLSessionDataDelegate>, <NSURLSessionDownloadDelegate>, 和 <NSURLSessionDelegate>这几个协议的协议方法。同时实现NSSecureCodingNSCopying来实现归档解档和copy功能。

2.1 AFURLSessionManager的初始化api

这些api主要用于初始化、安全策略、网络状态监听等:

interface AFURLSessionManager : NSObject <NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate, NSSecureCoding, NSCopying>
//指定的初始化方法、通过他来初始化一个Manager对象。
- (instancetype)initWithSessionConfiguration:(nullable NSURLSessionConfiguration *)configuration 
//AFURLSessionManager通过session来管理和创建网络请求。一个manager就实现了对这个session的管理,他们是一一对应的关系。
@property (readonly, nonatomic, strong) NSURLSession *session;
//处理网络请求回调的操作队列,就是我们初始化session的时候传入的那个OperationQueue参数。如果不传入,默认是MainOperationQueue。
@property (readonly, nonatomic, strong) NSOperationQueue *operationQueue;
//对返回数据的处理都通过这个属性来处理,比如数据的提取、转换等。默认是一个`AFJSONResponseSerializer`对象用JSON的方式解析。
@property (nonatomic, strong) id <AFURLResponseSerialization> responseSerializer;
//用于指定session的安全策略。用于处理信任主机和证书认证等。默认是`defaultPolicy`。
@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;
//观测网络状态的变化,具体可以看我的Demo用法。
@property (readwrite, nonatomic, strong) AFNetworkReachabilityManager *reachabilityManager;
@end

2.2 AFURLSessionManager获取Task的api

这部分api主要是任务的创建、任务的分类、任务完成队列处理、特殊情况的任务重新创建等:

//当前session创建的所有Task,这个是下面三种task的总和。
@property (readonly, nonatomic, strong) NSArray <NSURLSessionTask *> *tasks;
//当前session创建的DataTask
@property (readonly, nonatomic, strong) NSArray <NSURLSessionDataTask *> *dataTasks;
//当前session创建的uploadTask
@property (readonly, nonatomic, strong) NSArray <NSURLSessionUploadTask *> *uploadTasks;
//当前session创建的downloadTask
@property (readonly, nonatomic, strong) NSArray <NSURLSessionDownloadTask *> *downloadTasks;

//用于处理任务回调的GCD对象,默认是dispatch_main_queue。
@property (nonatomic, strong, nullable) dispatch_queue_t completionQueue;
//用于处理任务回调的GCD的group对象,如果不初始化、则一个默认的Group被使用。
@property (nonatomic, strong, nullable) dispatch_group_t completionGroup;
//在iOS7的环境下,我们通过background模式的session创建的uploadTask有时会是nil,如果这个属性是yes,AFN会尝试再次创建uploadTask。
@property (nonatomic, assign) BOOL attemptsToRecreateUploadTasksForBackgroundSessions;
//废除manager对应的Session。通过传入的参数来决定是否立即取消已经用session发出去的任务。
- (void)invalidateSessionCancelingTasks:(BOOL)cancelPendingTasks;

2.3 AFURLSessionManager为管理Task创建Block

AFURLSessionManager提供了很多创建Task的api。并且提供了很多处理Task的Block。应该说着几个api就是AFN为我们提供的最大价值,他把所有delegate方法细节都处理好。直接提供给我们一些最实用的api,我们就不用去管理session系列繁琐的delegate方法了。

//创建一个NSURLSessionDataTask
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
                            completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject,  NSError * _Nullable error))completionHandler;
//创建一个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;

//创建一个上传Task,并且指定上传文件的路径。
- (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;
////创建一个上传Task,并且指定上传的数据。
- (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;
//创建一个uploadTask,然后上传数据
- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request
                                                 progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
                                        completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;
//新建一个download任务,destination表示的下载文件的缓存路径
- (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;
//继续恢复一个download任务。resumeData参数表示的是恢复下载的时候初始化数据,比如前面已经下载好的部分数据。
- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData
                                                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;
//获取指定Task的上传进度
- (nullable NSProgress *)uploadProgressForTask:(NSURLSessionTask *)task;
//获取指定Task的下载进度
- (nullable NSProgress *)downloadProgressForTask:(NSURLSessionTask *)task;

注意:上面所有Task的progress都不在主线程、所以要在progress中做UI更新,都必须手动在主线程操作。

2.4 AFURLSessionManager设置各种情况的代理回调

这些回调Block主要是用于处理网络请求过程或者结束以后的数据处理、认证、通知、缓存等。我们可以通过设置这些Block来获取或者检测各种状态。相当于就是钩子函数。通过下面的这些Block,我们基本可以获取请求过程中的所有状态以及需要做的各种处理。

//设置Session出错或者无效的手的回调Block。这个Block主要在`NSURLSessionDelegate`代理的`URLSession:didBecomeInvalidWithError:`方法中执行。
- (void)setSessionDidBecomeInvalidBlock:(nullable void (^)(NSURLSession *session, NSError *error))block{
    
}
//当网络请需要的认证信息比如用户名密码已经发送了的时候,就可以通过这个Block来处理。这个Block是在`NSURLSessionDelegate`代理里面的`URLSession:didReceiveChallenge:completionHandler:`方法中被执行。注意这个是针对Session
- (void)setSessionDidReceiveAuthenticationChallengeBlock:(nullable NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * _Nullable __autoreleasing * _Nullable credential))block{
    
}
////当网络请需要的认证信息比如用户名密码已经发送了的时候,就可以通过这个Block来处理。这个Block是在`NSURLSessionTaskDelegate`代理里面的`URLSession:task:didReceiveChallenge:completionHandler:`方法中被执行。注意这个是针对Task。
- (void)setTaskDidReceiveAuthenticationChallengeBlock:(nullable NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, NSURLCredential * _Nullable __autoreleasing * _Nullable credential))block{
    
}
//当请求需要一个新的bodystream的时候,就可以通过这个Block来设置。这个Block在`NSURLSessionTaskDelegate` 代理协议的`URLSession:task:needNewBodyStream:`方法里面设置。
- (void)setTaskNeedNewBodyStreamBlock:(nullable NSInputStream * (^)(NSURLSession *session, NSURLSessionTask *task))block{
    
}
//当一个网络请求需要重定向的时候。就会调用这个Block。这个Block是在`NSURLSessionTaskDelegate`协议的`URLSession:willPerformHTTPRedirection:newRequest:completionHandler:`方法中调用的。
- (void)setTaskWillPerformHTTPRedirectionBlock:(nullable NSURLRequest * (^)(NSURLSession *session, NSURLSessionTask *task, NSURLResponse *response, NSURLRequest *request))block{
    
}
//可以通过设置这个Block来获取上传进度。这个Block主要在`NSURLSessionTaskDelegate`协议的 `URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:`方法中调用.
- (void)setTaskDidSendBodyDataBlock:(nullable void (^)(NSURLSession *session, NSURLSessionTask *task, int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend))block{
    
}
//设置一个Task完成以后执行的Block,这个Block在`NSURLSessionTaskDelegate`协议的 `URLSession:task:didCompleteWithError:`方法中执行。
- (void)setTaskDidCompleteBlock:(nullable void (^)(NSURLSession *session, NSURLSessionTask *task, NSError * _Nullable error))block{
    
}
//当接收到网络请求返回以后,可以调用这个Block。这个Block是在`NSURLSessionDataDelegate`协议的 `URLSession:dataTask:didReceiveResponse:completionHandler:`
- (void)setDataTaskDidReceiveResponseBlock:(nullable NSURLSessionResponseDisposition (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLResponse *response))block{
    
}
//如果一个dataTask转换为downLoadTask以后,就可以设置这个Block来调用。在`NSURLSessionDataDelegate` 协议的`URLSession:dataTask:didBecomeDownloadTask:`方法中调用。
- (void)setDataTaskDidBecomeDownloadTaskBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLSessionDownloadTask *downloadTask))block{
    
}
//当dataTask接收到数据以后,可以设置调用这个Block。具体在`NSURLSessionDataDelegate`协议的`URLSession:dataTask:didReceiveData:`方法。
- (void)setDataTaskDidReceiveDataBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSData *data))block{
    
}
//设置一个Block来决定是否处理或者换成网络请求缓存。具体在`NSURLSessionDataDelegate`协议的`URLSession:dataTask:willCacheResponse:completionHandler:`方法中。
- (void)setDataTaskWillCacheResponseBlock:(nullable NSCachedURLResponse * (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSCachedURLResponse *proposedResponse))block{
    
}
//当session所有的任务都发送出去以后,就可以通过这个Block来获取。具体在`NSURLSessionDataDelegate`协议的 `URLSessionDidFinishEventsForBackgroundURLSession:`方法中。
- (void)setDidFinishEventsForBackgroundURLSessionBlock:(nullable void (^)(NSURLSession *session))block{
    
}
//当一个downloadTask执行完毕以后,可以通过这个Block来获取下载信息,我们可以通过这个Block获取下载文件的位置。具体在`NSURLSessionDownloadDelegate`协议的`URLSession:downloadTask:didFinishDownloadingToURL:`方法中被调用。
- (void)setDownloadTaskDidFinishDownloadingBlock:(nullable NSURL * _Nullable  (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location))block{
    
}
//可以通过这个Block获取一个downloadTask的下载进度。这个Block会在下载过程中多次被调用。具体是在`NSURLSessionDownloadDelegate`协议中的`URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesWritten:totalBytesExpectedToWrite:`方法中被调用。
- (void)setDownloadTaskDidWriteDataBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite))block{
    
}
//当一个downloadTask重新开始以后,我们可以通过这个Block获取fileOffSet等信息获取已经下载的部分以及总共有多少要下载。具体是在`NSURLSessionDownloadDelegate`协议的`URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes:`方法中被调用。
- (void)setDownloadTaskDidResumeBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t fileOffset, int64_t expectedTotalBytes))block{
    
}

除了上面的部分,AFURLSessionManager的头文件还提供了很多notification的声明。通过这些通知,我们可以获取Task是否开始、是否完成、是否挂起、是否无效等各种通知。具体可以去文件里看。

3 AFURLSessionManager的实现分析

AFURLSessionManager.m文件里面除了有AFURLSessionManager.h定义的各种接口的实现意外,还有处理不同iOS版本下NSRULSession不同的部分,以及多个全局dispatch_queue_t的定义、以及处理NSURLSeesionTash的各种代理方法的实现和处理。具体划分如下:

  • NSURLSessionManager的实现。主要实现了接口文件定义的各种api的实现,比如Task的创建、Task的获取、Task的各种代理方法的实现、NSCoping和NSCoding协议、以及各种Block的实现。
    • 基本属性的初始化。比如sessionConfigurationoperationQueuesessionmutableTaskDelegatesKeyedByTaskIdentifier等属性。以及用于实现task和AFURLSessionManagerTaskDelegate的绑定的taskDescriptionForSessionTasks、还有关键操作的锁属性lock。
    • 接口文件的各种Block对应的属性,一个Block对应一个属性。
    • 处理Task暂停与重启操作的方法。
    • 给Task设置AFURLSessionManagerTaskDelegate代理的方法。
    • 初始化Task的各种方法。
    • 设置B接口文件定义的各种Block。
    • NSURLSession系列代理方法。
  • _AFURLSessionTaskSwizzling私有类。主要实现了iOS7和iOS8系统上NSURLSession差别的处理。让不同系统版本NSURLSession版本基本一致。
  • AFURLSessionManagerTaskDelegate这个类主要是把NSURLSeesion的部分代理方法让他处理。从而达到简化代码的目的。
    • 处理Task的上传或者下载进度。
    • 处理封装NSURLSeesion返回的数据。
    • Task完成等的通知封装。
  • 全局dispatch_queue_tdispatch_group_t的定义。各种通知名称的初始化,各种Block的类型定义。

3.1 AFURLSessionManager一个网络请求实现过程

我们通过一个网络请求过程来分析AFURLSessionManager.m的实现。我们通过initWithSessionConfiguration方法初始化一个manager。在这个方法里会初始化各种属性、以及为session属性设置代理:

接口文件中的代码如下:

 AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];

实现文件中对应的处理如下:

/**
 初始化方法
 @return 返回一个manager对象
 */
- (instancetype)init {
    return [self initWithSessionConfiguration:nil];
}
/**
 默认初始化方法、通过这个方法来做manager的具体化初始化动作

 @param configuration NSURLSession的配置
 @return 返回一个manager对象
 */
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
    self = [super init];
    if (!self) {
        return nil;
    }
    //如果用户没有手动指定,则使用默认的configuration来初始化
    if (!configuration) {
        configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    }
    //赋值给属性
    self.sessionConfiguration = configuration;
    //初始化NSURLSession的task代理方法执行的队列。
    //这里有一个很关键的点是task的代理执行的queque一次性只能执行一个task。这样就避免了task的代理方法执行的混乱。
    self.operationQueue = [[NSOperationQueue alloc] init];
    self.operationQueue.maxConcurrentOperationCount = 1;
    //出丝滑NSURLSession对象,最核心的对象。
    self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];
    //如果用户没有手动指定,则返回的数据是JSON格式序列化。
    self.responseSerializer = [AFJSONResponseSerializer serializer];
    //指定https处理的安全策略。
    self.securityPolicy = [AFSecurityPolicy defaultPolicy];
#if !TARGET_OS_WATCH
    //初始化网络状态监听属性
    self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
#endif
    //用于记录Task与他的`AFURLSessionManagerTaskDelegate`代理对象的一一对应关系。通过这个
    self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];
    //初始化一个锁对象,关键操作加锁。
    self.lock = [[NSLock alloc] init];
    self.lock.name = AFURLSessionManagerLockName;
    /**
     获取当前session正在执行的所有Task。同时为每一个Task添加`AFURLSessionManagerTaskDelegate`代理对象,这个代理对象主要用于管理uplaodTak和downloadTask的进度管理。并且在Task执行完毕以后调用相应的Block。同时发送相应的notification对象,实现对task数据或者状态改变的检测。
     @param dataTasks dataTask列表
     @param uploadTasks uplaodTask列表
     @param downloadTasks downloadTask列表
     @return
     */
    [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;
}

请求执行,接口文件如下:

NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:^(NSProgress *downloadProgress){
    NSLog(@"下载进度:%lld",downloadProgress.completedUnitCount);
} destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
    NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
    NSURL *fileURL = [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]];
    NSLog(@"fileURL:%@",[fileURL absoluteString]);
    return fileURL;
} completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
    self.imageView.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:filePath]];
    NSLog(@"File downloaded to: %@", filePath);
}];

实现文件则调用了很多方法:

1 首先是初始化一个NSURLSessionDownLoadTask对象

    //通过session创建一个downloadTask,
    __block NSURLSessionDownloadTask *downloadTask = nil;
    //url_session_manager_create_task_safely作用是修复在iOS8下面的系统bug。
    url_session_manager_create_task_safely(^{
        downloadTask = [self.session downloadTaskWithRequest:request];
    });
    [self addDelegateForDownloadTask:downloadTask progress:downloadProgressBlock destination:destination completionHandler:completionHandler];
    return downloadTask;

2 通过[self addDelegateForDownloadTask:downloadTask progress:downloadProgressBlock destination:destination completionHandler:completionHandler];这句话来为Task设置一个AFURLSessionManagerTaskDelegate代理对象。从而可以实现对进度处理、Block调用、Task完成返回数据的拼装的功能。

    //根据指定的Task,初始化一个AFURLSessionManagerTaskDelegate
    AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:downloadTask];
    delegate.manager = self;
    //设置Task完成的回调Block
    delegate.completionHandler = completionHandler;
    if (destination) {
        //任务完成以后,调用destination这个Block
        delegate.downloadTaskDidFinishDownloading = ^NSURL * (NSURLSession * __unused session, NSURLSessionDownloadTask *task, NSURL *location) {
            return destination(location, task.response);
        };
    }
    //指定Task与taskDescriptionForSessionTasks的关联关系,方便后面的通知中做对应的处理。
    downloadTask.taskDescription = self.taskDescriptionForSessionTasks;
    //添加通知
    [self setDelegate:delegate forTask:downloadTask];
    //设置一个下载进度的Block,以便在后面代理方法中调用。
    delegate.downloadProgressBlock = downloadProgressBlock;

3 初始化一个AFURLSessionManagerTaskDelegate对象。在这个对象中对Task的请求过程进行处理和控制。

/**
 初始化一个AFURLSessionManagerTaskDelegate对象
 @param task 对象绑定的Task
 @return 返回对象
 */
- (instancetype)initWithTask:(NSURLSessionTask *)task {
    self = [super init];
    if (!self) {
        return nil;
    }
    //这个属性用于存储Task下载过程中的数据
    _mutableData = [NSMutableData data];
    //存储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对象取消的时候,取消Task
        progress.cancellationHandler = ^{
            [weakTask cancel];
        };
        progress.pausable = YES;
        progress.pausingHandler = ^{
            //挂起Task
            [weakTask suspend];
        };
        if ([progress respondsToSelector:@selector(setResumingHandler:)]) {
            progress.resumingHandler = ^{
                //重启Task
                [weakTask resume];
            };
        }
        //更具progress的进度来获取Task的进度。fractionCompleted方法在请求过程中多次执行。
        [progress addObserver:self
                   forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
                      options:NSKeyValueObservingOptionNew
                      context:NULL];
    }
    return self;
}
//上面通过对fractionCompleted方法KVO。则会调用下面的方法,从而执行manager的
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
   if ([object isEqual:self.downloadProgress]) {
       //更新下载进度Block
        if (self.downloadProgressBlock) {
            self.downloadProgressBlock(object);
        }
    }else if ([object isEqual:self.uploadProgress]) {
        //更新上传进度Bloc
        if (self.uploadProgressBlock) {
            self.uploadProgressBlock(object);
        }
    }
}

4 在AFURLSessionManagerTaskDelegate设置Task状态改变的监听。

/**
 设置指定task的`AFURLSessionManagerTaskDelegate`对象。并且添加task挂起或者重启的监听。
 @param delegate 代理对象
 @param task task
 */
- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
            forTask:(NSURLSessionTask *)task
{
    NSParameterAssert(task);
    NSParameterAssert(delegate);
    //加锁操作
    [self.lock lock];
    //为Task设置与之代理方法关联关系。通过一个字典
    self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
    //添加对Task开始、重启、挂起状态的通知的接收。
    [self addNotificationObserverForTask:task];
    [self.lock unlock];
}
/**
 给Task添加任务开始、重启、挂起的通知

 @param task 任务
 */
- (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];
}

5 从下面开始,任务就正式开始执行。其实就是[downloadTask resume];执行以后开始。

/**
 在网络请求正式开始以后,这个方法会在数据接收的过程中多次调用。我们可以通过这个方法获取数据下载的大小、总得大小、还有多少么有下载
 @param session session
 @param downloadTask 对应的Task
 @param bytesWritten 已经下载的字节
 @param totalBytesWritten 总的字节大小
 @param totalBytesExpectedToWrite nil
 */
- (void)URLSession:(NSURLSession *)session
      downloadTask:(NSURLSessionDownloadTask *)downloadTask
      didWriteData:(int64_t)bytesWritten
 totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
    //获取Task对应的`AFURLSessionManagerTaskDelegate`对象。从而可以调用对应的代理方法
    AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask];
    if (delegate) {
        //调用`AFURLSessionManagerTaskDelegate`类中的代理方法。从而实现对于进度更新等功能。
        //会调用下面的那个方法
        [delegate URLSession:session downloadTask:downloadTask didWriteData:bytesWritten totalBytesWritten:totalBytesWritten totalBytesExpectedToWrite:totalBytesExpectedToWrite];
    }
    if (self.downloadTaskDidWriteData) {
        //如果有`downloadTaskDidWriteData`Block的实现,则在这个调用Block从而实现对下载进度过程的控制。
        self.downloadTaskDidWriteData(session, downloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
    }
}
//AFURLSessionManagerTaskDelegate里面的这个代理方法实现对进度的更新。
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
      didWriteData:(int64_t)bytesWritten
 totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{
    //AFURLSessionManagerTaskDelegate代理方法实现对下载进度的记录
    self.downloadProgress.totalUnitCount = totalBytesExpectedToWrite;
    self.downloadProgress.completedUnitCount = totalBytesWritten;
}

6 Task完成以后,会调用AFURLSessionManagerTaskDelegate对象的方法对返回的数据封装。

//AFURLSessionManagerTaskDelegate里面的这个代理方法实现对数据的具体处理。
- (void)URLSession:(__unused NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
    //获取Task对应的manager对象
    __strong AFURLSessionManager *manager = self.manager;
    //要封装的responseObject对象。
    __block id responseObject = nil;
    __block NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
    userInfo[AFNetworkingTaskDidCompleteResponseSerializerKey] = manager.responseSerializer;
    //返回的数据。
    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;
    }
    //如果是downloadTask,则封装downloadFileURL
    if (self.downloadFileURL) {
        userInfo[AFNetworkingTaskDidCompleteAssetPathKey] = self.downloadFileURL;
    } else if (data) {//如果是其他Task,则封装返回的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(), ^{
            //如果Task有completionHandler。则调用这个Block
            if (self.completionHandler) {
                self.completionHandler(task.response, responseObject, error);
            }
            //发送一个指定Task结束的通知
            dispatch_async(dispatch_get_main_queue(), ^{
                [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
            });
        });
    } else {//正确数据封装
        //在一个并行的dispat_queuq_t对象里面异步处理。
        dispatch_async(url_session_manager_processing_queue(), ^{
            NSError *serializationError = nil;
            //封装responseBojct
            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(), ^{
                //如果Task有完成Block。则调用这个Block
                if (self.completionHandler) {
                    self.completionHandler(task.response, responseObject, serializationError);
                }
                //发送通知
                dispatch_async(dispatch_get_main_queue(), ^{
                    [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
                });
            });
        });
    }
}

7 移除Task对应的通知和对应的AFURLSessionManagerTaskDelegate代理对象。

- (void)removeDelegateForTask:(NSURLSessionTask *)task {
    NSParameterAssert(task);
    [self.lock lock];
    //移除Task对应的通知
    [self removeNotificationObserverForTask:task];
    //移除Task对应的`AFURLSessionManagerTaskDelegate`代理对象。
    [self.mutableTaskDelegatesKeyedByTaskIdentifier removeObjectForKey:@(task.taskIdentifier)];
    [self.lock unlock];
}
//移除通知监听
- (void)removeNotificationObserverForTask:(NSURLSessionTask *)task {
    [[NSNotificationCenter defaultCenter] removeObserver:self name:AFNSURLSessionTaskDidSuspendNotification object:task];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:AFNSURLSessionTaskDidResumeNotification object:task];
}
//`AFURLSessionManagerTaskDelegate`对象回收。
- (void)dealloc {
    [self.downloadProgress removeObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted))];
    [self.uploadProgress removeObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted))];
}

通过上面的过程,我们发现核心流程都是围绕了NSRULSessionTask对象以及与之绑定的AFURLSessionManagerTaskDelegate对象执行的。我们通过在NSRULSessionTask对象的代理方法里面手动调用AFURLSessionManagerTaskDelegate对应的代理方法来实现对数据的处理和简化代码的作用,这个设计思路的确吊吊的。还有一些方法没有涉及到,不过大同小异,基本过程就是这样,就不一一解释了。

3.2 AFURLSessionManager一些特殊模块的说明

AFURLSeeesionManager实现了NSSecureCoding协议。让manager可以归档解档。

/**
 在iOS8以及以上环境下,supportsSecureCoding必须重写并且返回true。
 @return bool
 */
+ (BOOL)supportsSecureCoding {
    return YES;
}
//解档
- (instancetype)initWithCoder:(NSCoder *)decoder {
    NSURLSessionConfiguration *configuration = [decoder decodeObjectOfClass:[NSURLSessionConfiguration class] forKey:@"sessionConfiguration"];
    self = [self initWithSessionConfiguration:configuration];
    if (!self) {
        return nil;
    }
    return self;
}
/**
 我们发现对象归档的时候,只归档了`NSURLSessionConfiguration`属性。所以说归档接档的时候所有Block设置、operation设置都会失效。
 @param coder coder
 */
- (void)encodeWithCoder:(NSCoder *)coder {
    [coder encodeObject:self.session.configuration forKey:@"sessionConfiguration"];
}

同时,AFURLSessionManager也实现了NSCopying协议。通过协议的实现过程,我们发现也是只使用了NSURLSessionConfiguration属性。和归档解档一样。

#pragma mark - 实现NSCopying协议。copy的NAURLSessionManager没有复制任何与代理处理相关的Block
- (instancetype)copyWithZone:(NSZone *)zone {
    return [[[self class] allocWithZone:zone] initWithSessionConfiguration:self.session.configuration];
}

有的时候,我们的请求会返回302这个状态码,这个表示需要请求重定向到另一个url,我们可以下面这个代理方法里面决定对于重定向的处理,如果对completionHandler传入nil,则会把response传入重定向请求。另外,backgroundSession的Task不会调用下面这个代理方法,而是直接调用。

/**
 有的时候,我们的请求会返回302这个状态码,这个表示需要请求重定向到另一个url,我们可以在这个代理方法里面绝定对于重定向的处理。
 @param session session
 @param task task
 @param response response
 @param request 重定向的request。
 @param completionHandler 请求完成
 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest *))completionHandler
{
    //重定向的request对象
    NSURLRequest *redirectRequest = request;
    //如果用户指定了taskWillPerformHTTPRedirection这个Block,我们就通过这个Block的调用返回处理完成的request对象。
    if (self.taskWillPerformHTTPRedirection) {
        redirectRequest = self.taskWillPerformHTTPRedirection(session, task, response, request);
    }
    //这个调用是必须的,执行重定向操作。
    if (completionHandler) {
        completionHandler(redirectRequest);
    }
}

创建NSRULSessionUplaodTask的时候,在某些系统上会出现bug。AFN已经帮我们处理好:

- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
    __block NSURLSessionUploadTask *uploadTask = nil;
    //用线程安全的方式创建一个dataTask。修复iOS8下面的bug。
    url_session_manager_create_task_safely(^{
        uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL];
    });
    //用于处理uploadTask在iOS7环境下面有可能创建失败的情况。如果attemptsToRecreateUploadTasksForBackgroundSessions为true。则尝试重新创建Task。如果三次都没有成功,则放弃。
    if (!uploadTask && self.attemptsToRecreateUploadTasksForBackgroundSessions && self.session.configuration.identifier) {
        for (NSUInteger attempts = 0; !uploadTask && attempts < AFMaximumNumberOfAttemptsToRecreateBackgroundSessionUploadTask; attempts++) {
            uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL];
        }
    }
    //为Task添加`AFURLSessionManagerTaskDelegate`代理方法
    [self addDelegateForUploadTask:uploadTask progress:uploadProgressBlock completionHandler:completionHandler];
    return uploadTask;
}

通过使用dispatch_semaphore_t来控制对异步处理返回结果的控制。非常有借鉴意义。

#pragma mark -  获取当前session对应的task列表。通过dispatch_semaphore_t来控制访问过程。
- (NSArray *)tasksForKeyPath:(NSString *)keyPath {
    __block NSArray *tasks = nil;
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
        if ([keyPath isEqualToString:NSStringFromSelector(@selector(dataTasks))]) {
            tasks = dataTasks;
        } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(uploadTasks))]) {
            tasks = uploadTasks;
        } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(downloadTasks))]) {
            tasks = downloadTasks;
        } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(tasks))]) {
            tasks = [@[dataTasks, uploadTasks, downloadTasks] valueForKeyPath:@"@unionOfArrays.self"];
        }
        //这里发送一个信号量,让semaphore变为1。此时表示tasks已经成功获取。
        dispatch_semaphore_signal(semaphore);
    }];
    //这里会一直等待信号量变为1。
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    //返回Task。通过信号量控制,避免了方法结束的时候,tasks还没有正常获取的情况。
    return tasks;
}

4 _AFURLSessionTaskSwizzling私有类的说明

在iOS7和iOS8及以上的系统,NSRULSessionTask的具体实现是不同的。我们目前知道的不同有:

  • NSURLSessionTasks是一个类簇。所以我们初始化一个Task的时候,我们并不只到初始化的到底是哪个子类。
  • 简单的通过[NSURLSessionTask class]并不会起作用。必须通过NSURLSession创建一个task对象。然后获取他所在的类。
  • iOS7下面,下面代码中的localDataTask对象的继承关系是__NSCFLocalDataTask -> __NSCFLocalSessionTask -> __NSCFURLSessionTask
  • 在iOS8以及以上系统。下面代码中的localDataTask对象的继承关系是__NSCFLocalDataTask -> __NSCFLocalSessionTask -> NSURLSessionTask
  • 在iOS7下面__NSCFLocalSessionTask__NSCFURLSessionTask实现了resumesuspend方法,同时最重要的是他不调用父类的实现。但是iOS8下面,只有NSURLSessionTask实现了resumesuspend。所以在iOS7的环境下,我们需要想办法让resumesuspend调用NSURLSessionTask的具体实现。

下面的代码完美的向我们展示了一个向类添加方法,并且swizzle方法实现的过程。值得仔细琢磨。

/**
 切换theClass类的`originalSelector`和`swizzledSelector`的实现
 @param theClass 类
 @param originalSelector 方法一
 @param swizzledSelector 方法2
 */
static inline void af_swizzleSelector(Class theClass, SEL originalSelector, SEL swizzledSelector) {
    Method originalMethod = class_getInstanceMethod(theClass, originalSelector);
    Method swizzledMethod = class_getInstanceMethod(theClass, swizzledSelector);
    method_exchangeImplementations(originalMethod, swizzledMethod);
}
/**
 动态给一个类添加方法
 @param theClass 类
 @param selector 方法名字
 @param method 方法体
 @return bool
 */
static inline BOOL af_addMethod(Class theClass, SEL selector, Method method) {
    return class_addMethod(theClass, selector,  method_getImplementation(method),  method_getTypeEncoding(method));
}
@implementation _AFURLSessionTaskSwizzling
+ (void)load {
    if (NSClassFromString(@"NSURLSessionTask")) {
        NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
        NSURLSession * session = [NSURLSession sessionWithConfiguration:configuration];
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnonnull"
        //初始化一个dataTask对象
        NSURLSessionDataTask *localDataTask = [session dataTaskWithURL:nil];
#pragma clang diagnostic pop
        //获取af_resume这个方法的实现。
        IMP originalAFResumeIMP = method_getImplementation(class_getInstanceMethod([self class], @selector(af_resume)));
        //获取dataTask的具体类
        Class currentClass = [localDataTask class];
        //如果父类有resume方法。则改变方法的具体实现。
        while (class_getInstanceMethod(currentClass, @selector(resume))) {
            Class superClass = [currentClass superclass];
            //找到类和父类的resume方法实现
            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];
    }
}
/**
 主要是实现了为一个类添加方法、并且转换添加方法和原来对应方法的实现。
 @param theClass 要操作的类
 */
+ (void)swizzleResumeAndSuspendMethodForClass:(Class)theClass {
    Method afResumeMethod = class_getInstanceMethod(self, @selector(af_resume));
    Method afSuspendMethod = class_getInstanceMethod(self, @selector(af_suspend));
    //为theClass类添加一个af_resume方法。
    if (af_addMethod(theClass, @selector(af_resume), afResumeMethod)) {
        //把dataTask的resume和afresume方法的实现互换。
        af_swizzleSelector(theClass, @selector(resume), @selector(af_resume));
    }
    //为theClass类添加一个af_suspend方法
    if (af_addMethod(theClass, @selector(af_suspend), afSuspendMethod)) {
        //把dataTask的suspend和af_suspend方法的实现互换。
        af_swizzleSelector(theClass, @selector(suspend), @selector(af_suspend));
    }
}
- (NSURLSessionTaskState)state {
    NSAssert(NO, @"State method should never be called in the actual dummy class");
    return NSURLSessionTaskStateCanceling;
}
/**
 在iOS7下面,`NSURLSessionDataTask`调用resume方法其实就是执行`af_resume`的具体实现。
 */
- (void)af_resume {
    NSAssert([self respondsToSelector:@selector(state)], @"Does not respond to state");
    NSURLSessionTaskState state = [self state];
    //这里其实就是调用dataTask的resume实现
    [self af_resume];
    if (state != NSURLSessionTaskStateRunning) {
        //这里的self其实就是`NSRULSessionDataTask`对象
        [[NSNotificationCenter defaultCenter] postNotificationName:AFNSURLSessionTaskDidResumeNotification object:self];
    }
}
/**
 在iOS7下面,`NSURLSessionDataTask`调用suspend方法其实就是执行`af_suspend`的具体实现。
 */
- (void)af_suspend {
    NSAssert([self respondsToSelector:@selector(state)], @"Does not respond to state");
    NSURLSessionTaskState state = [self state];
    //这里其实就是调用dataTask的suspend具体实现
    [self af_suspend];
    if (state != NSURLSessionTaskStateSuspended) {
        //这里的self其实就是`NSRULSessionDataTask`对象
        [[NSNotificationCenter defaultCenter] postNotificationName:AFNSURLSessionTaskDidSuspendNotification object:self];
    }
}
@end

5 总结

AFURLSessionManager通过对task设置一个AFURLSessionManagerTaskDelegate代理来处理繁杂的请求进度管理。从而降低了代码的负责度。是代理模式的一个很好的实践。

AFURLSessionManager通过私有类_AFURLSessionTaskSwizzling来修改iOS7和iOS8系统上面不同。是对于方法swizzle的一个成功和完整的实践。

AFURLSessionManager通过添加各种Block,让我们对请求过程有全方位的控制和处理。同时提供简洁的api,把负责的处理全部封装好。

具体源码在iOSSourceCodeStudy

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容