iOS网络——AFNetworking AFHttpSessionManager源码解析
你要知道的NSURLSession都在这里
转载请注明出处 https://cloud.tencent.com/developer/user/1605429
本系列文章主要讲解iOS中网络请求类NSURLSession的使用方法进行详解,同时也会以此为扩展,讲解SDWebImage中图片下载功能的源码分析,讲解AFNetworking相关源码分析。本系列文章主要分为以下几篇进行讲解,读者可按需查阅。
- iOS网络——NSURLSession详解及SDWebImage源码解析
- iOS网络——SDWebImage SDImageDownloader源码解析
- iOS网络——AFNetworking AFURLSessionManager源码解析
- iOS网络——AFNetworking AFHttpSessionManager源码解析
AFNetworking AFHTTPSessionManager源码解析
前一篇文章我们讲解了AFURLSessionManager
的源码,最后还给了一个只使用AFURLSessionManager
来创建NSURLSessionDataTask
和NSURLSessionDownloadTask
的栗子,但是发现创建下载任务真的很简单了,只需要传入要下载文件的NSURL对象
,在传入几个回调块就能将文件下载到指定的目录中,并且可以监控下载进度,真的很方便,但NSURLSessionDataTask
创建的任务默认是GET
请求,如果需要其他如POST
请求还需要修改request
就显得有些麻烦了,今天要介绍的AFHTTPSessionManager
就是继承自AFURLSessionManager
,通过名称就知道这个类为HTTP
访问提供了更加便捷的方法。
直接看头文件的声明源码:
//继承自AFURLSessionManager类
@interface AFHTTPSessionManager : AFURLSessionManager <NSSecureCoding, NSCopying>
//网络请求要访问的URL
@property (readonly, nonatomic, strong, nullable) NSURL *baseURL;
//请求序列化
@property (nonatomic, strong) AFHTTPRequestSerializer <AFURLRequestSerialization> * requestSerializer;
//响应序列化
@property (nonatomic, strong) AFHTTPResponseSerializer <AFURLResponseSerialization> * responseSerializer;
///-------------------------------
/// @name Managing Security Policy
///-------------------------------
//安全策略
@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;
///---------------------
/// @name Initialization
///---------------------
//类方法返回一个AFHTTPSessionManager对象,不是单例,每次调用都重新创建
+ (instancetype)manager;
//构造函数
- (instancetype)initWithBaseURL:(nullable NSURL *)url;
//构造函数
- (instancetype)initWithBaseURL:(nullable NSURL *)url
sessionConfiguration:(nullable NSURLSessionConfiguration *)configuration NS_DESIGNATED_INITIALIZER;
///---------------------------
/// @name Making HTTP Requests
///---------------------------
//获取一个GET请求
- (nullable NSURLSessionDataTask *)GET:(NSString *)URLString
parameters:(nullable id)parameters
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure DEPRECATED_ATTRIBUTE;
//获取一个GET请求
- (nullable NSURLSessionDataTask *)GET:(NSString *)URLString
parameters:(nullable id)parameters
progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgress
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
//获取一个HEAD请求
- (nullable NSURLSessionDataTask *)HEAD:(NSString *)URLString
parameters:(nullable id)parameters
success:(nullable void (^)(NSURLSessionDataTask *task))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
//获取一个POST请求
- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(nullable id)parameters
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure DEPRECATED_ATTRIBUTE;
//获取一个POST请求
- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(nullable id)parameters
progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
//获取一个POST请求
- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(nullable id)parameters
constructingBodyWithBlock:(nullable void (^)(id <AFMultipartFormData> formData))block
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure DEPRECATED_ATTRIBUTE;
//获取一个POST请求
- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(nullable id)parameters
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;
//获取一个PUT请求
- (nullable NSURLSessionDataTask *)PUT:(NSString *)URLString
parameters:(nullable id)parameters
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
//获取一个PATCH请求
- (nullable NSURLSessionDataTask *)PATCH:(NSString *)URLString
parameters:(nullable id)parameters
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
//获取一个DELETE请求
- (nullable NSURLSessionDataTask *)DELETE:(NSString *)URLString
parameters:(nullable id)parameters
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
@end
AFHTTPSessionManager
提供了一系列的构造方法以及HTTP访问的方法。
@interface AFHTTPSessionManager ()
@property (readwrite, nonatomic, strong) NSURL *baseURL;
@end
@implementation AFHTTPSessionManager
@dynamic responseSerializer;
//类方法,返回一个新创建的AFHTTPSessionManager对象
+ (instancetype)manager {
return [[[self class] alloc] initWithBaseURL:nil];
}
//构造函数
- (instancetype)init {
return [self initWithBaseURL:nil];
}
//构造函数
- (instancetype)initWithBaseURL:(NSURL *)url {
return [self initWithBaseURL:url sessionConfiguration:nil];
}
//构造函数
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
return [self initWithBaseURL:nil sessionConfiguration:configuration];
}
//构造函数
- (instancetype)initWithBaseURL:(NSURL *)url
sessionConfiguration:(NSURLSessionConfiguration *)configuration
{
//调用父类的构造函数
self = [super initWithSessionConfiguration:configuration];
if (!self) {
return nil;
}
// Ensure terminal slash for baseURL path, so that NSURL +URLWithString:relativeToURL: works as expected
if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) {
url = [url URLByAppendingPathComponent:@""];
}
self.baseURL = url;
//获取单例的请求序列化和响应序列化器
self.requestSerializer = [AFHTTPRequestSerializer serializer];
self.responseSerializer = [AFJSONResponseSerializer serializer];
return self;
}
#pragma mark -
//setter
- (void)setRequestSerializer:(AFHTTPRequestSerializer <AFURLRequestSerialization> *)requestSerializer {
NSParameterAssert(requestSerializer);
_requestSerializer = requestSerializer;
}
//setter
- (void)setResponseSerializer:(AFHTTPResponseSerializer <AFURLResponseSerialization> *)responseSerializer {
NSParameterAssert(responseSerializer);
[super setResponseSerializer:responseSerializer];
}
@dynamic securityPolicy;
//setter设置安全策略
- (void)setSecurityPolicy:(AFSecurityPolicy *)securityPolicy {
if (securityPolicy.SSLPinningMode != AFSSLPinningModeNone && ![self.baseURL.scheme isEqualToString:@"https"]) {
NSString *pinningMode = @"Unknown Pinning Mode";
switch (securityPolicy.SSLPinningMode) {
case AFSSLPinningModeNone: pinningMode = @"AFSSLPinningModeNone"; break;
case AFSSLPinningModeCertificate: pinningMode = @"AFSSLPinningModeCertificate"; break;
case AFSSLPinningModePublicKey: pinningMode = @"AFSSLPinningModePublicKey"; break;
}
NSString *reason = [NSString stringWithFormat:@"A security policy configured with `%@` can only be applied on a manager with a secure base URL (i.e. https)", pinningMode];
@throw [NSException exceptionWithName:@"Invalid Security Policy" reason:reason userInfo:nil];
}
[super setSecurityPolicy:securityPolicy];
}
上面的方法就是一系列构造函数,用于初始化父类对象以及序列化器,设置安全策略等,没有太多复杂的内容。
//GET请求,调用下面那个方法
- (NSURLSessionDataTask *)GET:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
{
return [self GET:URLString parameters:parameters progress:nil success:success failure:failure];
}
//GET请求
- (NSURLSessionDataTask *)GET:(NSString *)URLString
parameters:(id)parameters
progress:(void (^)(NSProgress * _Nonnull))downloadProgress
success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure
{
//调用另一个方法构造GET请求
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"GET"
URLString:URLString
parameters:parameters
uploadProgress:nil
downloadProgress:downloadProgress
success:success
failure:failure];
/*
启动任务
使用AFHTTPSessionManager创建的任务默认都帮你启动了,所以不需要手动调用resume方法了
上一篇中讲解的AFURLSessionManager默认没有启动,所以获取任务后要手动启动
*/
[dataTask resume];
return dataTask;
}
//获取HEAD请求
- (NSURLSessionDataTask *)HEAD:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(NSURLSessionDataTask *task))success
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
{
//同样调用下面的一个方法来获取
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"HEAD" URLString:URLString parameters:parameters uploadProgress:nil downloadProgress:nil success:^(NSURLSessionDataTask *task, __unused id responseObject) {
if (success) {
success(task);
}
} failure:failure];
//默认启动任务
[dataTask resume];
return dataTask;
}
//获取POST请求
- (NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
{
//调用下面的方法获取
return [self POST:URLString parameters:parameters progress:nil success:success failure:failure];
}
//获取POST请求
- (NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(id)parameters
progress:(void (^)(NSProgress * _Nonnull))uploadProgress
success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure
{
//同GET HEAD方法一样,调用一个方法获取任务
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"POST" URLString:URLString parameters:parameters uploadProgress:uploadProgress downloadProgress:nil success:success failure:failure];
//默认启动任务
[dataTask resume];
return dataTask;
}
//获取POST上传文件请求
- (NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(nullable id)parameters
constructingBodyWithBlock:(nullable void (^)(id<AFMultipartFormData> _Nonnull))block
success:(nullable void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure
{
//调用下面的方法来构造上传文件的POST请求
return [self POST:URLString parameters:parameters constructingBodyWithBlock:block progress:nil success:success failure:failure];
}
//上传文件POST请求
- (NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(id)parameters
constructingBodyWithBlock:(void (^)(id <AFMultipartFormData> formData))block
progress:(nullable void (^)(NSProgress * _Nonnull))uploadProgress
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
{
//构造一个request请求
NSError *serializationError = nil;
NSMutableURLRequest *request = [self.requestSerializer multipartFormRequestWithMethod:@"POST" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters constructingBodyWithBlock:block error:&serializationError];
//如果在做序列化时出错在主线程调用failure回调块
if (serializationError) {
if (failure) {
dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
failure(nil, serializationError);
});
}
return nil;
}
//调用父类的方法获取一个上传的任务
__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;
}
//获取PUT请求
- (NSURLSessionDataTask *)PUT:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
{
//通过一个通用的方法来获取dataTask
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"PUT" URLString:URLString parameters:parameters uploadProgress:nil downloadProgress:nil success:success failure:failure];
//默认启动任务
[dataTask resume];
return dataTask;
}
//同上
- (NSURLSessionDataTask *)PATCH:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
{
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"PATCH" URLString:URLString parameters:parameters uploadProgress:nil downloadProgress:nil success:success failure:failure];
[dataTask resume];
return dataTask;
}
//同上
- (NSURLSessionDataTask *)DELETE:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
{
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"DELETE" URLString:URLString parameters:parameters uploadProgress:nil downloadProgress:nil success:success failure:failure];
[dataTask resume];
return dataTask;
}
//一个通用的方法来构造NSURLSessionDataTask
- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress
success:(void (^)(NSURLSessionDataTask *, id))success
failure:(void (^)(NSURLSessionDataTask *, NSError *))failure
{
//通过请求序列化器构造一个request请求
//需要传入请求方法GET POST DELETE PUT这样的字符串 以及相关参数
NSError *serializationError = nil;
NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
//如果序列化失败在主线程中执行failure回调块
if (serializationError) {
if (failure) {
dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
failure(nil, serializationError);
});
}
return nil;
}
//序列化成功,调用父类的方法获取dataTask
__block NSURLSessionDataTask *dataTask = nil;
dataTask = [self dataTaskWithRequest:request
uploadProgress:uploadProgress
downloadProgress:downloadProgress
completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
if (error) {
if (failure) {
failure(dataTask, error);
}
} else {
if (success) {
success(dataTask, responseObject);
}
}
}];
//返回dataTask
return dataTask;
}
上面的代码也很简单,是在AFURLSessionManager
之上做了一些处理,其中涉及的AFURLRequestSerialization
和AFURLResponseSerialization
由于不是本系列文章的关注点所以没有相关讲解,有需要的读者请自行查阅。
AFHTTPSessionManager
继承自AFURLSessionManager
并提供了更加便捷的网络请求接口,如果阅读了前一篇AFURLSessionManager
可以发现它才是重点。AFHTTPSessionManager
只是在它的基础上做了一些简单的封装,提供了更加便捷的接口。
通过AFURLSessionManager
和AFHTTPSessionManager
源码的阅读可以学习到AFNetworking
在代码设计方面的优点,以及对NSURLSession
的使用更清晰了。
备注
由于作者水平有限,难免出现纰漏,如有问题还请不吝赐教。
- HttpClient(二)HttpClient使用Ip代理与处理连接超时
- JavaScript中匿名函数的困惑
- 基础野:细说有符号整数
- Ubuntu14.04下如何开启Mysql远程访问
- docker学习(7) docker-compose使用示例
- docker学习(3) 容器的启动过程
- 基础野:细说原码、反码和补码
- JavaScript循环读书笔记
- docker学习(2) mac中docker-machine使用vmware fusion以及配置国内镜像加速
- HttpClient(一)HttpClient抓取网页基本信息
- Httpd运维日志:通过apxs添加模块
- 探索客户端JavaScript
- docker学习(8) 在mac机上搭建私有仓库
- Jsoup(一)Jsoup详解(官方)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法