这是第二篇内容,其他内容可以看下方链接:
- 第一部分是请求和响应的对应代码,包括
AFURLRequestSerialization
、AFURLResponseSerialization
- 第二部分是URLSession有关的代码,包括
AFURLSessionManager
和AFHTTPSessionManager
; - 第三部分是辅助的两个类:
AFSecurityPolicy
和AFNetworkReachabilityManager
; - 第四部分是
UIKit+AFNetworking
目录下的有趣内容。
AFURLSessionManager类
这个类用于创建和管理NSURLSession
对象,遵守了NSURLSession
相关的协议并实现了大部分代理方法。AFURLSessionManager
类中会持有一个NSURLSession
对象,而session
中每一个task
对象又会被一个字典属性管理,字典的key
为task.taskIdentifier
,value
为AFURLSessionManagerTaskDelegate
对象。delegate
对象负责每个task
对象成功后的回调工作。
大致了解一下结构之后,我们来看具体的代码,先是这个类的声明:
// 持有的session对象,每一个manager都有一个session
@property (readonly, nonatomic, strong) NSURLSession *session;
// session协议回调的执行队列,串行队列
@property (readonly, nonatomic, strong) NSOperationQueue *operationQueue;
// response序列化器,默认的是json序列化器
@property (nonatomic, strong) id <AFURLResponseSerialization> responseSerializer;
@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;
#if !TARGET_OS_WATCH
@property (readwrite, nonatomic, strong) AFNetworkReachabilityManager *reachabilityManager;
#endif
// task完成之后,进行回调的队列,默认是主线程队列
@property (nonatomic, strong, nullable) dispatch_queue_t completionQueue;
// task完成之后的group,默认内部创建,group的目的还是外部可以通过notify来监听
@property (nonatomic, strong, nullable) dispatch_group_t completionGroup;
接下来是获取task
数组的属性声明:
// 这四个属性都是通过session.getTasksWithCompletionHandler方法获取的,后面会简单看下
@property (readonly, nonatomic, strong) NSArray <NSURLSessionTask *> *tasks;
@property (readonly, nonatomic, strong) NSArray <NSURLSessionDataTask *> *dataTasks;
@property (readonly, nonatomic, strong) NSArray <NSURLSessionUploadTask *> *uploadTasks;
@property (readonly, nonatomic, strong) NSArray <NSURLSessionDownloadTask *> *downloadTasks;
再往下是方法的声明:
// 使用configuration对象进行初始化
// configuration比较常用的是default和background,另外还有不涉及缓存等操作的ephemeral
- (instancetype)initWithSessionConfiguration:(nullable NSURLSessionConfiguration *)configuration NS_DESIGNATED_INITIALIZER;
// 失效session对象
// cancelPendingTasks:立即取消排队中的task
// resetSession:重置session对象
- (void)invalidateSessionCancelingTasks:(BOOL)cancelPendingTasks resetSession:(BOOL)resetSession;
/* --- 以下是创建task的方法 --- */
// 创建task的方法有好几个,大致就是不同的入参格式,都比较容易理解,不做赘述了
- (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;
// 下载方法中的destination参数,主要用法是将下载的tmp文件路径和response信息交予我们,我们告知AFN具体要保存到哪个path
- (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;
/* ------ */
// 根据task来返回进度,这个进度是通过delegate对象保管的
- (nullable NSProgress *)uploadProgressForTask:(NSURLSessionTask *)task;
- (nullable NSProgress *)downloadProgressForTask:(NSURLSessionTask *)task;
/* --- 以下是一些回调block,有些忽略了,主要列了一些在触发block的同时,也会把事件透传到delegate对象中的方法 ---*/
// 上传数据时周期性触发,显示具体上传了多少字节,会透传到delegate更新具体task的进度
- (void)setTaskDidSendBodyDataBlock:(nullable void (^)(NSURLSession *session, NSURLSessionTask *task, int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend))block;
// task完成后触发,同时也会透传到delegate,delegate负责通知调用方,具体逻辑稍后再看
- (void)setTaskDidCompleteBlock:(nullable void (^)(NSURLSession *session, NSURLSessionTask *task, NSError * _Nullable error))block;
// 使用普通task对象下载时收到数据会多次触发(片段下载),透传delegate更新下载进度,需要手动去保存下载的片段数据
- (void)setDataTaskDidReceiveDataBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSData *data))block;
// 使用downloadTask对象下载完成后通过此block可以重设存储路径后通知delegate
- (void)setDownloadTaskDidFinishDownloadingBlock:(nullable NSURL * _Nullable (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location))block;
// 使用downloadTask对象下载并本地持久化时触发,透传delegate更新下载进度
- (void)setDownloadTaskDidWriteDataBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite))block;
// 续传下载时,透传delegate更新下载进度
- (void)setDownloadTaskDidResumeBlock:(nullable void (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t fileOffset, int64_t expectedTotalBytes))block;
...
/* ------ */
通过代码结构可以看到实现文件中除了AFURLSessionManager
类之外,还声明了AFURLSessionManagerTaskDelegate
和_AFURLSessionTaskSwizzling
两个类,所以我们再看下这两个类做了什么,首先是_AFURLSessionTaskSwizzling
:
// 两个静态方法,用来交换方法和添加方法
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);
}
static inline BOOL af_addMethod(Class theClass, SEL selector, Method method) {
return class_addMethod(theClass, selector, method_getImplementation(method), method_getTypeEncoding(method));
}
+ (void)load {
// 此处官方注释有详细解释,大致就是说dataTask对象在iOS7和iOS8的继承父类不同,所以只能用这种遍历的方式,把父类和本类resume实现不一致的类进行替换,替换为AFN自己的resume和suspend方法
// 此处通过一个空类实现+load方式,在程序运行前进行方法替换
if (NSClassFromString(@"NSURLSessionTask")) {
// 使用短暂配置的session对象,创建一个localDataTask
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];
// 循环遍历这个task的父类,交换所有方法
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];
}
}
+ (void)swizzleResumeAndSuspendMethodForClass:(Class)theClass {
// 获取空类中自定义方法
Method afResumeMethod = class_getInstanceMethod(self, @selector(af_resume));
Method afSuspendMethod = class_getInstanceMethod(self, @selector(af_suspend));
// 将方法加入到class后,交换原始方法
if (af_addMethod(theClass, @selector(af_resume), afResumeMethod)) {
af_swizzleSelector(theClass, @selector(resume), @selector(af_resume));
}
if (af_addMethod(theClass, @selector(af_suspend), afSuspendMethod)) {
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;
}
- (void)af_resume {
NSAssert([self respondsToSelector:@selector(state)], @"Does not respond to state");
NSURLSessionTaskState state = [self state];
[self af_resume];
// 注意此时的state为NSURLSessionTaskStateSuspended
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];
// 注意此时的state为NSURLSessionTaskStateRunning
if (state != NSURLSessionTaskStateSuspended) {
[[NSNotificationCenter defaultCenter] postNotificationName:AFNSURLSessionTaskDidSuspendNotification object:self];
}
}
这个类无非就是使用自定义的resume
和suspend
方法替换原始方法,目的就是在操作之后,从task
对象发送通知到AFURLSessionManager
中,再由AFURLSessionManager
发送通知到外部调用方。
我并没有弄清楚此处自定义方法中的state
状态变化,猜测是调用resume
或者suspend
方法后state
并没有立即改变,如果有研究的大佬可以与我交流。
接下来,我们继续看另一个AFURLSessionManagerTaskDelegate
类。这个类的目的是用来针对每一个task
对象进行具体操作和响应的,如其名为代理者,正是设计模式中的代理模式
的实际事例,我们看下其声明:
// 此类遵守NSURLSession相关协议,方便外部直接调用协议方法
@interface AFURLSessionManagerTaskDelegate : NSObject <NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate>
// 使用task对象初始化,task用于progress的回调操作
- (instancetype)initWithTask:(NSURLSessionTask *)task;
// 弱引用manager对象
@property (nonatomic, weak) AFURLSessionManager *manager;
// 用来保存接收到的数据对象
@property (nonatomic, strong) NSMutableData *mutableData;
// 上传进度
@property (nonatomic, strong) NSProgress *uploadProgress;
// 下载进度
@property (nonatomic, strong) NSProgress *downloadProgress;
// 下载存储地址
@property (nonatomic, copy) NSURL *downloadFileURL;
#if AF_CAN_INCLUDE_SESSION_TASK_METRICS
// 任务数据采集
@property (nonatomic, strong) NSURLSessionTaskMetrics *sessionTaskMetrics AF_API_AVAILABLE(ios(10), macosx(10.12), watchos(3), tvos(10));
#endif
// 各种回调
@property (nonatomic, copy) AFURLSessionDownloadTaskDidFinishDownloadingBlock downloadTaskDidFinishDownloading;
@property (nonatomic, copy) AFURLSessionTaskProgressBlock uploadProgressBlock;
@property (nonatomic, copy) AFURLSessionTaskProgressBlock downloadProgressBlock;
@property (nonatomic, copy) AFURLSessionTaskCompletionHandler completionHandler;
@end
声明类中的属性都比较直观,我们看下具体的实现逻辑:
- (instancetype)initWithTask:(NSURLSessionTask *)task {
...
_mutableData = [NSMutableData data];
_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的相关配置省略掉
...
// 对progress变化进行监控
[progress addObserver:self
forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
options:NSKeyValueObservingOptionNew
context:NULL];
}
return self;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
// 进度发生变化时,通过block通知外部调用方
if ([object isEqual:self.downloadProgress]) {
if (self.downloadProgressBlock) {
self.downloadProgressBlock(object);
}
}
...
}
// URLSession请求完成回调
- (void)URLSession:(__unused NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
// 优先取身份挑战的error
error = objc_getAssociatedObject(task, AuthenticationChallengeErrorKey) ?: error;
__strong AFURLSessionManager *manager = self.manager;
__block id responseObject = nil;
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
userInfo[AFNetworkingTaskDidCompleteResponseSerializerKey] = manager.responseSerializer;
// 下载数据完成时会copy为不可变对象,优化内存的写法
NSData *data = nil;
if (self.mutableData) {
data = [self.mutableData copy];
self.mutableData = nil;
}
...
// 使用downloadTask对象时,会有file url;使用dataTask对象下载时会有data。
if (self.downloadFileURL) {
userInfo[AFNetworkingTaskDidCompleteAssetPathKey] = self.downloadFileURL;
} else if (data) {
userInfo[AFNetworkingTaskDidCompleteResponseDataKey] = data;
}
if (error) {
...
} else {
dispatch_async(url_session_manager_processing_queue(), ^{
NSError *serializationError = nil;
// 通过session manager中的response序列化器进行数据序列化
responseObject = [manager.responseSerializer responseObjectForResponse:task.response data:data error:&serializationError];
// 如果是downloadTask下载任务则使用文件路径
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(), ^{
// 请求成功后,在指定的group和queue中进行回调
if (self.completionHandler) {
self.completionHandler(task.response, responseObject, serializationError);
}
// 主线程发送通知,外部同样是主线程接收通知
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
});
});
});
}
}
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {
self.downloadFileURL = nil;
// 如果存在task自身的设置,则使用自身的设置来获取file url。
// 可以看到delegate对象中存在downloadTaskDidFinishDownloading回调,session manager中同样存在
// 里面有很多这种写法,既可以让session manager统一设置,也可以让delegate自行设置
if (self.downloadTaskDidFinishDownloading) {
self.downloadFileURL = self.downloadTaskDidFinishDownloading(session, downloadTask, location);
if (self.downloadFileURL) {
NSError *fileManagerError = nil;
if (![[NSFileManager defaultManager] moveItemAtURL:location toURL:self.downloadFileURL error:&fileManagerError]) {
[[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDownloadTaskDidFailToMoveFileNotification object:downloadTask userInfo:fileManagerError.userInfo];
} else {
[[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDownloadTaskDidMoveFileSuccessfullyNotification object:downloadTask userInfo:nil];
}
}
}
}
现在两个简单的类看完了,这里一定要想清楚AFURLSessionManagerTaskDelegate
的作用是什么。接下来看下主体类AFURLSessionManager
的实现:
/* 隐式声明 */
@interface AFURLSessionManager ()
// session配置对象
@property (readwrite, nonatomic, strong) NSURLSessionConfiguration *sessionConfiguration;
// session delegate回调队列
@property (readwrite, nonatomic, strong) NSOperationQueue *operationQueue;
// manager持有的session对象
@property (readwrite, nonatomic, strong) NSURLSession *session;
// 用来管理每一个task对应的delegate,key为task.taskIdentifier,value为delegate对象
@property (readwrite, nonatomic, strong) NSMutableDictionary *mutableTaskDelegatesKeyedByTaskIdentifier;
// 当前session的地址
@property (readonly, nonatomic, copy) NSString *taskDescriptionForSessionTasks;
// mutableTaskDelegatesKeyedByTaskIdentifier的安全锁
@property (readwrite, nonatomic, strong) NSLock *lock;
...
@end
/* 实现 */
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
...
if (!configuration) {
configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
}
self.sessionConfiguration = configuration;
// 串行队列
self.operationQueue = [[NSOperationQueue alloc] init];
self.operationQueue.maxConcurrentOperationCount = 1;
// 默认json格式的response序列化器
self.responseSerializer = [AFJSONResponseSerializer serializer];
// 安全策略,默认none
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;
}
AFHTTPSessionManager
这个类就相对简单了,提供的都是发起HTTP
请求的一些便利方法,只需要大致一看即可:
// 使用NS_DESIGNATED_INITIALIZER修饰的指定初始化器,其他init方法可以当做便捷初始化器
- (instancetype)initWithBaseURL:(nullable NSURL *)url
sessionConfiguration:(nullable NSURLSessionConfiguration *)configuration NS_DESIGNATED_INITIALIZER;
// GET请求的快捷方法
- (nullable NSURLSessionDataTask *)GET:(NSString *)URLString
parameters:(nullable id)parameters
headers:(nullable NSDictionary <NSString *, NSString *> *)headers
progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgress
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
// POST请求上传数据的快捷方法
// 在constructingBodyWithBlock回调中的formData中添加需要上传的数据,上文讲解过
- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(nullable id)parameters
headers:(nullable NSDictionary <NSString *, NSString *> *)headers
constructingBodyWithBlock:(nullable void (^)(id <AFMultipartFormData> formData))block
progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
// 通用方法
- (nullable NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(nullable id)parameters
headers:(nullable NSDictionary <NSString *, NSString *> *)headers
uploadProgress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress
downloadProgress:(nullable void (^)(NSProgress *downloadProgress))downloadProgress
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
很简单对吧,我们浏览一遍实现文件:
- (instancetype)initWithBaseURL:(NSURL *)url
sessionConfiguration:(NSURLSessionConfiguration *)configuration {
...
// 此写法是为了保证url拼接不出错,可以看以下注释:
/*
NSURL *baseURL = [NSURL URLWithString:@"http://example.com/v1/"];
[NSURL URLWithString:@"foo" relativeToURL:baseURL]; // http://example.com/v1/foo
[NSURL URLWithString:@"foo?bar=baz" relativeToURL:baseURL]; // http://example.com/v1/foo?bar=baz
[NSURL URLWithString:@"/foo" relativeToURL:baseURL]; // http://example.com/foo
[NSURL URLWithString:@"foo/" relativeToURL:baseURL]; // http://example.com/v1/foo
[NSURL URLWithString:@"/foo/" relativeToURL:baseURL]; // http://example.com/foo/
[NSURL URLWithString:@"http://example2.com/" relativeToURL:baseURL]; // http://example2.com/
*/
if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) {
url = [url URLByAppendingPathComponent:@""];
}
self.baseURL = url;
// 默认HTTP请求序列化器和JSON响应序列化器
self.requestSerializer = [AFHTTPRequestSerializer serializer];
self.responseSerializer = [AFJSONResponseSerializer serializer];
return self;
}
- (NSURLSessionDataTask *)GET:(NSString *)URLString
parameters:(nullable id)parameters
headers:(nullable NSDictionary <NSString *, NSString *> *)headers
progress:(nullable void (^)(NSProgress * _Nonnull))downloadProgress
success:(nullable void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure {
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"GET" URLString:URLString parameters:parameters headers:headers uploadProgress:nil downloadProgress:downloadProgress success:success failure:failure];
[dataTask resume];
return dataTask;
}
- (NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(nullable id)parameters
headers:(nullable NSDictionary<NSString *,NSString *> *)headers
constructingBodyWithBlock:(nullable void (^)(id<AFMultipartFormData> _Nonnull))block
progress:(nullable void (^)(NSProgress * _Nonnull))uploadProgress
success:(nullable void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure {
NSError *serializationError = nil;
// 上传数据需要通过请求序列化器来初始化request
NSMutableURLRequest *request = [self.requestSerializer multipartFormRequestWithMethod:@"POST" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters constructingBodyWithBlock:block error:&serializationError];
// 设置请求头
for (NSString *headerField in headers.keyEnumerator) {
[request setValue:headers[headerField] forHTTPHeaderField:headerField];
}
if (serializationError) {
if (failure) {
dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
failure(nil, serializationError);
});
}
return nil;
}
// 调用父类的upload request方法进行上传
__block NSURLSessionDataTask *task = [self uploadTaskWithStreamedRequest:request progress:uploadProgress completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
if (error) {
if (failure) {
failure(task, error);
}
} else {
if (success) {
success(task, responseObject);
}
}
}];
[task resume];
return task;
}
- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(nullable id)parameters
headers:(nullable NSDictionary <NSString *, NSString *> *)headers
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure {
NSError *serializationError = nil;
// 对于非上传数据的请求,直接调用request序列化器生成普通的request
NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
for (NSString *headerField in headers.keyEnumerator) {
[request setValue:headers[headerField] forHTTPHeaderField:headerField];
}
if (serializationError) {
if (failure) {
dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
failure(nil, serializationError);
});
}
return nil;
}
__block NSURLSessionDataTask *dataTask = nil;
// 调用父类来生成普通的dataTask
dataTask = [self dataTaskWithRequest:request
uploadProgress:uploadProgress
downloadProgress:downloadProgress
completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
...
}];
return dataTask;
}
AFHTTPSessionManager
这个类非常的简单,却是我们使用中最直接用到的类,其内部包括了其他几个类的实例属性,属于大一统
的类。