文章目录
- 前言
- 一.原生的网络请求发送方式
- 1.1 原生GET
- 1.2 原生PSOT
- 二.AFN
- 2.1 AFN的基本架构分析
- 2.2 以GET为例分析AFN使用流程(AFHTTPSessionManager
- 2.2.1 AFN如何生生成对应的sessionManager
- 2.2.2. AFURLSessionManager的初始化
- 2.2.3 task的三种代理
- 2.2.3.1 setDelegate方法
- 2.2.4 AFN如何生生成对应的sessionManager总结
- 2.3 Mananger调用GET方法的流程解析
- 2.3.1 GET方法的执行过程
- 生成dataTask方法
- 在这个方法里面我们需要查看两个方法,我已经标注出来了。
- requestWithMethod:进行序列化处理
- dataTaskWithRequest:生成一个datatask任务
- completionHandler
- 总结
前言
源码库第二篇。
AFNetworking
这个框架是iOS必备的一个第三方框架,其高效简洁的API使其成为最好的iOS网络请求框架,也让iOS开发的网络请求轻松许多,对于原生的GET和POST请求,AFNetworking
这个框架提供了更方便的方法帮助了客户端和服务端的交互。
本次学习是基于AFNetworking4.0库,相比于3.0添加了请求头,因为在写项目的时候也发现不论是自己后端或者原生的后台API都需要写请求头这个东西。
请求头(Request Header)
是在HTTP请求中包含的一部分信息,用于向服务器传递关于请求的额外信息和参数。
一.原生的网络请求发送方式
由于NSURLConnection
已经被废弃,这里讲NSURLSession
。从GET和POST两种请求方式入手。
1.1 原生GET
步骤
- 确定请求路径
- 创建可变的请求对象
request
:可省略((默认包含了请求头和请求方法【Get】),此步骤可以省略). - 创建会话
session
对象 - 根据会话对象创建请求任务
datatask
,(利用dataTaskWithRequest
或者dataTaskWithURL
方法来进行创建) - 执行Task任务
- 当得到服务器返回的响应后,解析数据(XML、JSON、HTTP)如果返回的数据是JSON格式的,因此使用
NSJSONSerialization
进行反序列化处理
1.2 原生PSOT
- 对于原生的POST步骤,相比于GET多了一个请求头,并且原生POST不能省略request对象,因为需要在request添加请求头
- 确定请求的路径URL
- 创建可变的请求对象request:不可省略——POST请求需要设置请求头
- 设置请求头(需要对创建好的请求头进行序列化:确保为服务端可识别的数据格式)和请求方式POST
- 创建会话session对象
- 根据会话对象创建请求任务datatask——(通过dataTaskWithRequest)
- 执行Task
- 当得到服务器返回的响应后,解析数据(XML、JSON、HTTP)如果返回的数据是JSON格式的,因此使用NSJSONSerialization进行反序列化处理、
二.AFN
2.1 AFN的基本架构分析
AFN4.0和3.0的基本架构变化不大,整体分为图上的文件部分
NSURLSession
:网络请求的主要类,AFURLSessionManager
封装的是NSURLSession
,而AFHTTPSessionManager
是其子类,用于HTTP请求做了一些优化Reachability
:网络状况,AFNetworkReachabilityManager
是用来监测当前网络状况的一个类Security
:网络安全,HTTPS请求就要用到AFSecurityPolicy
Serialization
:序列化,AFURLRequestSerialization
是请求前的序列化,AFURLResponseSerialization
是请求完成后对结果的序列化UIKit
:里面则是一些UIkit的拓展Category
类和类的关系如下图所示
AFN的模块划分
- 通过使用和上述图解可以看出AFN的整体就是围绕着
AFURLSessionManager
来进行的。 AFNetWorking
大致分为一下五大模块,其中最为核心的是网络通信模块,主要用来发送和响应请求。AFNetworkReachabilityManager
主要是用来进行网络状态的监听,在不同网络状态下请求和响应的不同操作和处理;
为了保证网络请求的安全性,当然少不了AFSecurityPolicy
,网络安全策略模块,在初始化sessionmanger
的时候同时初始化了AFSecurityPolicy
以及网络通信信息请求序列化的类- 网络通信信息序列化模块分为请求序列化和响应序列化,其内部分别会对请求头和响应头进行编码,在请求的时候,将请求头转码为计算机可识别的格式,在响应的时候将响应结果进行转码后传回给客户端
- UIKit库的一些相关拓展,其中包括UIImageView的请求,UIButton的请求等等。
整个步骤也可以理解为下图
- 网络通信模块(AFURLSessionManager、AFHTTPSessionManager)
- 网络状态监听模块(AFNetworkReachabilityManager)
- 网络通信安全策略模块(AFSecurityPolicy)
- 网络通信信息序列化模块(AFURLRequestSerialization,AFURLResponseSerialization)
- iOS UIkit库的拓展(UIKit)
2.2 以GET为例分析AFN使用流程(AFHTTPSessionManager
以GET请求为例,以下是请求的代码。
- 生成对应的sessionManager;
- 调用GET方法进行请求;
- GET回调里边处理结果,包括(任务进度,请求成功的结果,请求失败的结果);
2.2.1 AFN如何生生成对应的sessionManager
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
跟着图解一步一步看
首先初始化,然后一步一步调用到父类的方法,我们分段看。
- 初始化,调用
initWithBaseURL
+ (instancetype)manager {
return [[[self class] alloc] initWithBaseURL:nil];
}
initWithBaseURL
调用initWithBaseURL:(NSURL *)url sessionConfiguration:
- (instancetype)initWithBaseURL:(NSURL *)url {
return [self initWithBaseURL:url sessionConfiguration:nil];
}
initWithBaseURL:(NSURL *)url sessionConfiguration:
实现分析
- (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
//条件判断了URL的路径是否具有长度大于0。它使用了[url path]方法来获取URL的路径,并通过length方法获取路径的长度。
// [[url absoluteString] hasSuffix:@"/"]:这个条件判断了URL的绝对字符串表示是否以斜杠("/")结尾。它使用了[url absoluteString]方法获取URL的绝对字符串表示,并通过hasSuffix:方法检查字符串是否以斜杠结尾。
if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) {
// 如果上述两个条件都为真(路径长度大于0且不以斜杠结尾),则执行以下代码块:
// url = [url URLByAppendingPathComponent:@""];:这行代码使用URLByAppendingPathComponent:方法将一个空路径组件追加到原始URL的路径末尾,从而确保URL的路径以斜杠结尾。
url = [url URLByAppendingPathComponent:@""];
}
self.baseURL = url;
self.requestSerializer = [AFHTTPRequestSerializer serializer];
self.responseSerializer = [AFJSONResponseSerializer serializer];
return self;
}
- 总体而言,这段代码的作用是检查URL的路径是否为空或不以斜杠结尾,如果不符合条件,则在路径末尾追加一个空路径组件,以确保URL的路径以斜杠结尾。
2.2.2. AFURLSessionManager的初始化
从上述的最后调用 self = [super initWithSessionConfiguration:configuration];
能看出来在最后AFHTTPSessionManager
中的初始化方法最终都会调用其父类的initWitchSessionConfiguration
初始化方法,返回一个sessionManager
方法;那么,需要去看一下父类也就是AFURLSessionManager
的初始化都做了什么
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
self = [super init];
if (!self) {
return nil;
}
if (!configuration) {
configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
/*
NSURLSessionConfiguration是用于配置NSURLSession的类。它提供了一系列属性和方法,用于定制和管理会话(session)的行为和特性。
defaultSessionConfiguration:返回一个默认的会话配置,可用于创建默认的NSURLSession实例。
*/
}
self.sessionConfiguration = configuration;
/// 初始化操作队列 并设置为串行队列 设置最大并发操作数
self.operationQueue = [[NSOperationQueue alloc] init];
/// ‼️队列的最大并发操作数设置为1,这里的并发操作数值的是回调代理的线程并发数。
/// ‼️在多线程编程中,操作队列(operation queue)是用于管理操作(operation)的一种机制。操作队列可以用来异步执行一系列任务,并控制它们的并发性。
/// 通过将最大并发操作数设置为 1,即 maxConcurrentOperationCount = 1,可以确保操作队列中的操作按顺序依次执行,而不会并发执行。这意味着每个操作将在上一个操作完成后才会开始执行。
self.operationQueue.maxConcurrentOperationCount = 1;
/// AFJSONResponseSerializer 用来序列化HTTP的响应
self.responseSerializer = [AFJSONResponseSerializer serializer];
/// 初始化SSI需要的 AFSecurityPolocy用来保证请求的安全性
self.securityPolicy = [AFSecurityPolicy defaultPolicy];
#if !TARGET_OS_WATCH
/// AFNetWorkRarchability Manager 查看网络连接情况
self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
#endif
/// ‼️初始化可变任务字典 任务task的id作为key 代理对象作为value
/// self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];是用来将每一个请求任务和自定义的AFURLSessionManagerTaskDelegate来建立映射的;(需要深入研究,代理和这里的关系,以及利用KVO的思想实现的相关)
self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];
// 锁的初始化并命名
self.lock = [[NSLock alloc] init];
self.lock.name = AFURLSessionManagerLockName;
/// ‼️ 在初始化的时候获取当前session中的所有task,为它们重新设置一遍代理;一般来说初始化的session中的task应该是为空的,这里这么做的主要目的是为了防止从后台回来的时候初始化session,对于一些后台之前的请求任务没有重设代理导致崩溃的问题
[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;
}
- 初始化当前的会话配置,操作队列,锁,
AFNetworkReachabilityManager
,AFSecurityPolicy
,请求序列化以及用来存储任务的可变任务字典等属性; - 获取当前session中所有未完成的task,给它们设置一遍代理;
- 需要注意‼️的地方:
-
self.mutableTaskDelegatesKeyedByTaskIdentifier
是一个可变的字典属性,用于将任务标识符(task identifier)与相应的任务委托对象进行关联
-
- ‼️在多线程编程中,操作队列(operation queue)是用于管理操作(operation)的一种机制。操作队列可以用来异步执行一系列任务,并控制它们的并发性。
-
- 通过将最大并发操作数设置为 1,即 maxConcurrentOperationCount = 1,可以确保操作队列中的操作按顺序依次执行,而不会并发执行。这意味着每个操作将在上一个操作完成后才会开始执行。
2.2.3 task的三种代理
对于不同的任务,AFN是如何完成网络请求,通过getTasksWithCompletionHandler
: 方法来获取当前会话(session)中的所有任务,并对每个任务添加相应的任务委托对象。
代码的执行流程如下:
- 调用
getTasksWithCompletionHandler:
方法,该方法接受一个完成处理程序块作为参数。 - 在完成处理程序块中,会收到三个参数
dataTasks
、uploadTasks
和downloadTasks
,它们分别表示当前会话中的数据任务、上传任务和下载任务。 - 使用
for-in
循环遍历dataTasks
数组,对每个NSURLSessionDataTask
类型的任务执行以下操作:- 调用
addDelegateForDataTask:uploadProgress:downloadProgress:completionHandler:
方法,将任务和相应的参数传递给该方法。 - 该方法将为数据任务添加一个任务委托对象,并根据需要设置上传和下载进度的回调以及任务完成的回调。
- 调用
- 使用
for-in
循环遍历uploadTasks
数组,对每个NSURLSessionUploadTask
类型的任务执行类似的操作:- 调用
addDelegateForUploadTask:progress:completionHandler:
方法,将任务和相应的参数传递给该方法。 - 该方法将为上传任务添加一个任务委托对象,并根据需要设置上传进度的回调以及任务完成的回调。
- 调用
- 使用
for-in
循环遍历downloadTasks
数组,对每个NSURLSessionDownloadTask
类型的任务执行类似的操作:- 调用
addDelegateForDownloadTask:progress:destination:completionHandler:
方法,将任务和相应的参数传递给该方法。 - 该方法将为下载任务添加一个任务委托对象,并根据需要设置下载进度、文件保存路径的回调以及任务完成的回调。
- 调用
通过getTasksWithCompletionHandler
方法,可以将适当的任务委托对象与每个任务关联起来,并对任务的执行过程进行跟踪和处理。
2.2.3.1 setDelegate方法
查看这三个代理方法的源码
通过观察三个代理方法的实现,到最后都会调用setDelegate:(AFURLSessionManagerTaskDelegate *)delegate forTask:(NSURLSessionTask *)task
方法 setDelegate:forTask:
的实现,用于为给定的 NSURLSessionTask
设置相应的 AFURLSessionManagerTaskDelegate
任务委托对象。
- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate
forTask:(NSURLSessionTask *)task
{
/// 首先,通过使用 NSParameterAssert 宏进行断言,确保 task 和 delegate 参数非空。这是一种防御性编程的做法,以确保传入的参数符合预期,避免在后续使用过程中出现问题。
NSParameterAssert(task);
NSParameterAssert(delegate);
/// 接下来,通过调用 [self.lock lock] 来获取一个锁,确保在多线程环境中对 self.mutableTaskDelegatesKeyedByTaskIdentifier 字典的操作是线程安全的。
[self.lock lock];
/// 将 delegate 任务委托对象与 task.taskIdentifier 任务标识符关联,并将其存储在 self.mutableTaskDelegatesKeyedByTaskIdentifier 字典中。使用 @(task.taskIdentifier) 将任务标识符转换为 NSNumber 对象作为字典的键。
self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
/// 调用 [self addNotificationObserverForTask:task] 方法,为任务添加通知观察者,以便在任务执行过程中获取相关通知,如任务完成、进度更新等。
[self addNotificationObserverForTask:task];
/// 最后,通过调用 [self.lock unlock] 释放锁,确保线程安全的访问完成。
[self.lock unlock];
}
该方法的作用是将指定的任务委托对象与任务关联起来,并将其存储在字典中以便后续使用。这样可以轻松地追踪和管理与每个任务相关的委托对象,以便进行任务状态跟踪、结果处理或其他相关操作
2.2.4 AFN如何生生成对应的sessionManager总结
至此,对于初始化的时候获取当前session
中的所有task
,已经为它们重新设置一遍代理。回到initWitchSessionConfiguration
方法中返回当前对象,向上返回,生成AFHTTPSessionManager *sessionMange
r对象;
2.3 Mananger调用GET方法的流程解析
还是以GET为例子,先看图解
2.3.1 GET方法的执行过程
- (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
{
/// 调用 dataTaskWithHTTPMethod:URLString:parameters:headers:uploadProgress:downloadProgress:success:failure: 方法,该方法创建一个 NSURLSessionDataTask 数据任务对象,用于执行指定的 HTTP GET 请求。将传入的参数传递给该方法以构建请求。
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"GET"
URLString:URLString
parameters:parameters
headers:headers
uploadProgress:nil
downloadProgress:downloadProgress
success:success
failure:failure];
/// 调用 [dataTask resume] 方法启动数据任务,使其开始执行。
[dataTask resume];
/// 返回数据任务对象 dataTask。
return dataTask;
参数:
URLString:请求的URL值
parameters:根据需求的请求参数
headers:请求头
downloadProgress:更新下载进度的对象
success:任务成功后执行的Block对象
failure:任务失败后执行的Block对象
}
代码的执行流程如下:
- 接收传入的
URLString
、parameters
、headers
、downloadProgress
、success
和failure
参数,它们分别表示请求的 URL 字符串、请求参数、请求头、下载进度回调、成功回调和失败回调。 - 调用
dataTaskWithHTTPMethod:URLString:parameters:headers:uploadProgress:downloadProgress:success:failure:
方法,该方法创建一个NSURLSessionDataTask
数据任务对象,用于执行指定的 HTTP GET 请求。将传入的参数传递给该方法以构建请求。 - 调用
[dataTask resume]
方法启动数据任务,使其开始执行。 - 返回数据任务对象
dataTask
。
通过这段代码,可以方便地发起一个 GET 请求,并且可以通过传入的参数来定制请求的 URL、参数、请求头等。同时,可以指定下载进度回调、成功回调和失败回调来处理请求的结果和状态。最后,代码中的 [dataTask resume]
启动任务,使其开始执行。
生成dataTask方法
dataTaskWithHTTPMethod:URLString:parameters:headers:uploadProgress:downloadProgress:success:failure:
该方法是生成datatask,是AFHTTPSessionManager
中的dataTaskWithHTTPMethod
方法
- (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;
/// 使用 `self.requestSerializer` 对象根据传入的参数构建一个 `NSMutableURLRequest` 可变请求对象。
/// self.requestSerializer:请求序列化器
/// ‼️‼️ 需要点进去的方法1
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];
}
/// // 如果在构建请求过程中出现了 `serializationError` 错误,即请求参数序列化错误,则会执行相应的错误处理逻辑。
if (serializationError) {
if (failure) {
/// 如果存在 `failure` 失败回调,则将错误通过异步方式回调到主队列上。
dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
failure(nil, serializationError);
});
}
return nil;
}
/// 创建一个 `NSURLSessionDataTask` 数据任务对象
__block NSURLSessionDataTask *dataTask = nil;
/// 并调用 `dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler:` 方法来配置任务的上传进度回调、下载进度回调和完成处理程序块。
// ‼️ 需要点进去的方法2
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);
}
}
}];
return dataTask;
}
dataTaskWithHTTPMethod:URLString:parameters:headers:uploadProgress:downloadProgress:success:failure:
方法的实现。该方法用于创建一个 NSURLSessionDataTask
数据任务对象,并配置请求的相关参数。
代码的执行流程如下:
- 接收传入的
method
、URLString
、parameters
、headers
、uploadProgress
、downloadProgress
、success
和failure
参数,它们分别表示请求的 HTTP 方法、URL 字符串、请求参数、请求头、上传进度回调、下载进度回调、成功回调和失败回调。 - 使用
self.requestSerializer
对象根据传入的参数构建一个NSMutableURLRequest
可变请求对象。请求的 URL 会根据URLString
和self.baseURL
进行拼接和转换。请求的参数和错误对象会由requestWithMethod:URLString:parameters:error:
方法返回。 - 遍历
headers
字典中的键值对,将键作为请求头字段,值作为请求头的值,通过setValue:forHTTPHeaderField:
方法设置到请求对象中。 - 如果在构建请求过程中出现了
serializationError
错误,即请求参数序列化错误,则会执行相应的错误处理逻辑。如果存在failure
失败回调,则将错误通过异步方式回调到主队列上。 - 创建一个
NSURLSessionDataTask
数据任务对象,并调用dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler:
方法来配置任务的上传进度回调、下载进度回调和完成处理程序块。 - 返回数据任务对象
dataTask
。
在这个方法里面我们需要查看两个方法,我已经标注出来了。
- 一个是
requestWithMethod
序列化处理 -
- 序列化处理的原因:在HTTp网络请求是基于字节流的网络传输,序列化是可以将一个对象转化成一段字节编码,以此方便在网络上传输或者做其他存储处理,使用的时候在对其做反序列化;简单的来说就是为了统一,我们可以用自己的方法来保存对象,但是在底层只提供一种保存对象状态的机制。因此我们在存储的时候需要进行序列化,以此来和提供的保持一致,在读取的时候对其进行反序列化,得到我们想要的形式;
- 一个是
dataTaskWithRequest
生成数据任务
requestWithMethod:进行序列化处理
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
error:(NSError *__autoreleasing *)error
{
/// 首先进行参数断言,确保传入的 method 和 URLString 不为 nil
NSParameterAssert(method);
NSParameterAssert(URLString);
/// 使用 NSURL 的 URLWithString: 方法将 URLString 转换为 NSURL 对象,然后进行参数断言,确保 url 不为 nil。
NSURL *url = [NSURL URLWithString:URLString];
NSParameterAssert(url);
/// 创建一个可变的 NSMutableURLRequest 请求对象,使用 initWithURL: 方法将 url 作为初始化参数,并将 method 赋值给请求对象的 HTTPMethod 属性。
NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url];
mutableRequest.HTTPMethod = method;
///遍历 AFHTTPRequestSerializerObservedKeyPaths() 方法返回的被观察的键路径,通过ketPath检查 self.mutableObservedChangedKeyPaths 是否包含该键路径,如果包含,则将 self 对象的对应键路径的值设置为请求对象的对应键路径的值。存到mutableRequest中
for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
if ([self.mutableObservedChangedKeyPaths containsObject:keyPath]) {
[mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath];
}
}
/// 调用 requestBySerializingRequest:withParameters:error: 方法,将请求对象和参数进行序列化,返回一个经过序列化处理的请求对象。如果出现错误,会将错误对象赋值给传入的 error 参数。
mutableRequest = [[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy];
///mutableCopy: 将序列化后的请求对象转换为可变的副本,并返回该对象。
return mutableRequest;
}
dataTaskWithRequest:生成一个datatask任务
- (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 {
/// 接收一个 NSURLRequest 对象作为请求参数,并使用该请求对象创建一个 NSURLSessionDataTask 对象,即 dataTask。
NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:request];
/// 调用 self 对象的 addDelegateForDataTask:uploadProgress:downloadProgress:completionHandler: 方法,为 dataTask 添加代理、上传进度回调、下载进度回调和完成处理块。这些参数分别是 uploadProgressBlock、downloadProgressBlock 和 completionHandler。
[self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];
return dataTask;
}
AFURLSessionManager
类的 dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler:
方法的实现。该方法用于创建一个 NSURLSessionDataTask
对象,并为该任务添加代理和相关的进度回调以及完成处理块。
completionHandler
completionHandler
是一个回调闭包,用于处理网络请求完成后返回的结果。它的定义为(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))
- 其中
response
是请求的响应对象,responseObject
是响应体数据(可以是NSData、NSDictionary等),error
是请求过程中出现的错误信息,如网络不可用、请求超时等。 - 在
dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler:
中,当网络请求完成后,会调用这个闭包处理请求结果。
总结
至此做完上述处理之后,最终将生成的dataTask返回到GET方法当中,这样最终在GET中就拿到了我们可以发送请求的task,最后调用系统方法[dataTask resume];发起网络请求;
对于AFURLSessionManager还有他遵守的很多代理是在我们进行网络请求的时候调用的,接下来学习AFURLSessionManager及其代理解析。