【AFNetWorking源码一】

news/2024/7/20 21:30:25 标签: ios, http, objective-c, 网络协议
http://www.w3.org/2000/svg" style="display: none;">

文章目录

  • 前言
  • 一.原生的网络请求发送方式
    • 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的基本架构分析

https://img-blog.csdnimg.cn/beebc8c4d83a4683a7fe70a988d367d8.png" alt="请添加图片描述" />

AFN4.0和3.0的基本架构变化不大,整体分为图上的文件部分

  • NSURLSession:网络请求的主要类,AFURLSessionManager封装的是NSURLSession,而AFHTTPSessionManager是其子类,用于HTTP请求做了一些优化
  • Reachability:网络状况,AFNetworkReachabilityManager是用来监测当前网络状况的一个类
  • Security:网络安全,HTTPS请求就要用到AFSecurityPolicy
  • Serialization:序列化,AFURLRequestSerialization是请求前的序列化,AFURLResponseSerialization是请求完成后对结果的序列化
  • UIKit:里面则是一些UIkit的拓展Category

类和类的关系如下图所示
https://img-blog.csdnimg.cn/ba49bcc312b04215a5fa1659d0bf6a14.png" alt="请添加图片描述" />
AFN的模块划分

  • 通过使用和上述图解可以看出AFN的整体就是围绕着AFURLSessionManager来进行的。
  • AFNetWorking大致分为一下五大模块,其中最为核心的是网络通信模块,主要用来发送和响应请求。
  • AFNetworkReachabilityManager主要是用来进行网络状态的监听,在不同网络状态下请求和响应的不同操作和处理;
    为了保证网络请求的安全性,当然少不了AFSecurityPolicy,网络安全策略模块,在初始化sessionmanger的时候同时初始化了AFSecurityPolicy以及网络通信信息请求序列化的类
  • 网络通信信息序列化模块分为请求序列化和响应序列化,其内部分别会对请求头和响应头进行编码,在请求的时候,将请求头转码为计算机可识别的格式,在响应的时候将响应结果进行转码后传回给客户端
  • UIKit库的一些相关拓展,其中包括UIImageView的请求,UIButton的请求等等。

整个步骤也可以理解为下图
https://img-blog.csdnimg.cn/a85b30a844684a7ebe8989ee5fbd2723.png" alt="在这里插入图片描述" />

  • 网络通信模块(AFURLSessionManager、AFHTTPSessionManager)
  • 网络状态监听模块(AFNetworkReachabilityManager)
  • 网络通信安全策略模块(AFSecurityPolicy)
  • 网络通信信息序列化模块(AFURLRequestSerialization,AFURLResponseSerialization)
  • iOS UIkit库的拓展(UIKit)

2.2 以GET为例分析AFN使用流程(AFHTTPSessionManager

以GET请求为例,以下是请求的代码。

  • 生成对应的sessionManager;
  • 调用GET方法进行请求;
  • GET回调里边处理结果,包括(任务进度,请求成功的结果,请求失败的结果);

https://img-blog.csdnimg.cn/6374584cb3954c56833d6c15f9af671c.png" alt="请添加图片描述" />

2.2.1 AFN如何生生成对应的sessionManager

AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

跟着图解一步一步看
https://img-blog.csdnimg.cn/a319a6ffd118423590a7c556870e7fb2.png" alt="在这里插入图片描述" />

首先初始化,然后一步一步调用到父类的方法,我们分段看。
https://img-blog.csdnimg.cn/4a21c27ba02647299f7e46d8ed015955.png" alt="在这里插入图片描述" />

  • 初始化,调用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;
}

  • 初始化当前的会话配置,操作队列,锁,AFNetworkReachabilityManagerAFSecurityPolicy,请求序列化以及用来存储任务的可变任务字典等属性;
  • 获取当前session中所有未完成的task,给它们设置一遍代理;
  • 需要注意‼️的地方:
    • self.mutableTaskDelegatesKeyedByTaskIdentifier 是一个可变的字典属性,用于将任务标识符(task identifier)与相应的任务委托对象进行关联
    • ‼️在多线程编程中,操作队列(operation queue)是用于管理操作(operation)的一种机制。操作队列可以用来异步执行一系列任务,并控制它们的并发性。
    • 通过将最大并发操作数设置为 1,即 maxConcurrentOperationCount = 1,可以确保操作队列中的操作按顺序依次执行,而不会并发执行。这意味着每个操作将在上一个操作完成后才会开始执行。

2.2.3 task的三种代理

对于不同的任务,AFN是如何完成网络请求,通过getTasksWithCompletionHandler: 方法来获取当前会话(session)中的所有任务,并对每个任务添加相应的任务委托对象。
https://img-blog.csdnimg.cn/75651ad3fff84198a9bd6109695c48fe.png" alt="请添加图片描述" />
代码的执行流程如下:

  • 调用 getTasksWithCompletionHandler: 方法,该方法接受一个完成处理程序块作为参数。
  • 在完成处理程序块中,会收到三个参数 dataTasksuploadTasksdownloadTasks,它们分别表示当前会话中的数据任务、上传任务和下载任务。
  • 使用 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方法

查看这三个代理方法的源码https://img-blog.csdnimg.cn/1dd4a6d4b58d4fba8c0060754e46c555.png" alt="请添加图片描述" />https://img-blog.csdnimg.cn/6021de6b0ef54336ab4b1165a6e1c857.png" alt="请添加图片描述" />
https://img-blog.csdnimg.cn/cec6bdeea757472d9fa9e4865a6108fe.png" alt="请添加图片描述" />
通过观察三个代理方法的实现,到最后都会调用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 *sessionManger对象;

2.3 Mananger调用GET方法的流程解析

还是以GET为例子,先看图解
https://img-blog.csdnimg.cn/d66700343bb340fa9b39138fef6d0b28.png" alt="在这里插入图片描述" />

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对象
}

代码的执行流程如下:

  • 接收传入的 URLStringparametersheadersdownloadProgresssuccessfailure 参数,它们分别表示请求的 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中的da taTaskWithHTTPMethod方法
- (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 数据任务对象,并配置请求的相关参数。

代码的执行流程如下:

  • 接收传入的 methodURLStringparametersheadersuploadProgressdownloadProgresssuccessfailure 参数,它们分别表示请求的 HTTP 方法、URL 字符串、请求参数、请求头、上传进度回调、下载进度回调、成功回调和失败回调。
  • 使用 self.requestSerializer 对象根据传入的参数构建一个 NSMutableURLRequest 可变请求对象。请求的 URL 会根据 URLStringself.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

https://img-blog.csdnimg.cn/96d85fa45d6b448792f912f6e997d6c2.png" alt="请添加图片描述" />

  • 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及其代理解析。


http://www.niftyadmin.cn/n/333290.html

相关文章

windows下安装emsdk

先从github上下载emsdk工程&#xff1a; # Get the emsdk repo git clone https://github.com/emscripten-core/emsdk.git# Enter that directory cd emsdkgit pull 更新到最新代码 clone 工程可以在 git bash here 命令行下&#xff1a; 执行下面的指令用cmd命令行&#xf…

Spring AOP的概念和使用

什么是AOP AOP是一种思想&#xff0c;它叫做面向切面编程&#xff0c;简单的来说就是对某一类事请做集中处理。比如说&#xff1a;登录效验功能&#xff0c;在使用AOP之前&#xff0c;我们进行登录效验需要在每个方法中写一遍登录效验的代码&#xff1b;使用AOP后&#xff0c;…

IBM 创新方案+SNP数据转型助一汽大众实现数据平稳、高效迁移

近日&#xff0c;IBM 采用基于SNP Bluefield技术迁移的IBM Rapid Move创新数据迁移方案, 成功为一汽-大众实施了企业运营数据系统从 ECC 到 S/4 的升级项目。该项目系统切换耗时仅三天&#xff0c;不仅助客户高效、平稳迁移了系统数据&#xff0c;升级了数据底座&#xff0c;还…

改进YOLOv5 | 在 C3 模块中添加【Triplet】【SpatialGroupEnhance】【NAM】【S2】注意力机制 | 附详细结构图

文章目录 1. Triplet 注意力模块1.1 原理1.2 C3_Triplet 代码2. SpatialGroupEnhance 注意力模块2.1 原理2.2 C3_SpatialGroupEnhance 代码3. NAM 注意力模块3.1 原理3.2 C3_NAM 代码4. S2 注意力模块4.1 原理4.2 C3_S2 代码5. 添加方式💡6. C3_Attention 结构图 &#x

chatgpt赋能Python-pycharm怎么编译python

PyCharm怎么编译Python&#xff1f; Python是当今最流行的编程语言之一&#xff0c;其简单易学、高效实用的特性使其受到了广大开发者的欢迎。PyCharm是一款专业的Python集成开发环境&#xff0c;它提供了许多有用的功能和工具&#xff0c;可以极大地提高开发效率。本文将介绍…

【计算机网络详解】——数据链路层(学习笔记)

&#x1f4d6; 前言&#xff1a;数据链路层提供了一种在不可靠的物理介质上传输数据的方式&#xff0c;并负责在网络层和物理层之间提供一个可靠的通信连接。本文将对数据链路层进行详细的介绍&#xff0c;包括数据链路层的定义、协议、功能和应用等方面。 目录 &#x1f552; …

chatgpt赋能Python-pycharm中怎么粘贴代码

PyCharm是Python编程领域中最受欢迎的集成开发环境之一。它是由JetBrains开发的一款跨平台IDE软件&#xff0c;旨在优化Python项目的开发过程。PyCharm拥有强大的代码编辑器、调试器、代码跟踪器和内置的版本控制工具&#xff0c;可以帮助开发人员编写高效、优质的Python代码。…

常见的两种通信方式

引言 随着后端服务的发展&#xff0c;业务难度增加&#xff1b;单体的后端服务逐渐满足不了快速迭代&#xff0c;敏捷开发的节奏&#xff0c;在这样的背景下&#xff0c;分布式系统架构思想逐渐发展&#xff0c;并流行起来&#xff1b;在微服务思想下&#xff0c;将原有复杂的…