当前位置: 首页 > news >正文

【AFNetWorking源码(二)AFURLSessionManger和AFHTTPSessionManager】

前言

学习了Mananger的初始化和以GET请求为例的过程,发现整个过程离不开AFHTTPSessionManager和AFURLSessionManger的某些方法。这两个是AFN的重要的网络通信模块内容,对它们作揖详细的学习。

AFURLSessionManagerAFHTTPSessionManager都是AFNetworking库中的两个类,用于处理网络请求和会话管理

如果只涉及到HTTP请求,一般会直接使用AFHTTPSessionManager进行操作。而AFURLSessionManager则提供了更底层的接口,适用于特定的定制需求或与NSURLSession相关的操作

1.1 AFURLSessionManger和AFHTTPSessionManager的关系

图解
在这里插入图片描述
首先AFURLSessionMangerAFHTTPSessionManager的父类,其中AFURLSessionManger内部还包含AFURLSessionManagerTaskDelegate_AFURLSessionTaskSwizzling

AFHTTPSessionManager本身是对网络请求做了一些简单的封装,请求的整个逻辑是分发给AFURLSessionManager或者其他类去做的;其内部管理自己的两种序列化工具,用来对请求和响应的数据做序列化;同时依赖于父类提供的保证安全,监控网络状态,实现发出HTTP请求的核心功能;

AFHTTPSessionManager也可以是AFURLSessionManager的基础上进一步封装,专门用于处理基于HTTP协议的网络请求,提供了更方便的HTTP请求方法和相关功能,如GET、POST等常见的HTTP方法,以及请求参数的设置、请求头的配置、数据解析等功能

1.2 AFURLSessionManager

1.2.1 AFURLSessionManger功能

AFURLSessionManager负责生成对应的NSURLSession的实例,管理AFNetworkReachabilityManagerAFSecurityPolicy,以此一来查看网络的连接情况,二来保证请求的安全,同时初始化生成一个AFJSONResponseSerializer的实例来序列化HTTP的响应结果;

遵守的协议

  • 点击发现他遵守了很多的协议
    请添加图片描述
    除此之外还提供了属性和方法用来完成其功能

关键属性

@property (nonatomic, strong) id <AFURLResponseSerialization> responseSerializer;
// 响应序列化// SSL的安全策略
@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;/// 网络监控
@property (readwrite, nonatomic, strong) AFNetworkReachabilityManager *reachabilityManager;

概览

在这里插入图片描述

核心方法就是生成一个AFURLSessionManager的实例对象,上文在以GET请求为例的时候介绍了dataTaskWithRequest,其实还有uploadTaskWithRequest和 downloadTaskWithRequest和downloadTaskWithResumeData

uploadTaskWithRequest

点击发现uploadTaskWithRequest存在三个不同的请求方法

  • uploadTaskWithRequest:(NSURLRequest *)requestfromFile
  • (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)requestfromData
  • (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest
/// 使用本地的文件请求创建一个NSURLSessionUploadTask
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)requestfromFile:(NSURL *)fileURLprogress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlockcompletionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{/// 它调用了request和本地的文件URL路径创建了一个uploadTaskNSURLSessionUploadTask *uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL];/// 为该uploadTask太溺爱对应的代理 addDelegateForUploadTaskif (uploadTask) {[self addDelegateForUploadTask:uploadTaskprogress:uploadProgressBlockcompletionHandler:completionHandler];}return uploadTask;
}/// 根据指定的HTTP Body请求创建URLSessionUploadTask
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)requestfromData:(NSData *)bodyDataprogress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlockcompletionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{NSURLSessionUploadTask *uploadTask = [self.session uploadTaskWithRequest:request fromData:bodyData];[self addDelegateForUploadTask:uploadTask progress:uploadProgressBlock completionHandler:completionHandler];return uploadTask;
}
/// AFURLSessionManager的一个方法,用于创建一个基于流的上传任务。具体参数说明如下:
/// request:上传请求,即要上传的数据和上传地址。
/// uploadProgressBlock:上传进度回调,NSProgress对象用于获取上传进度信息。
/// completionHandler:上传完成后的回调,包含上传的响应、响应数据和错误信息。
- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)requestprogress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlockcompletionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{/// 使用这个方法创建的上传任务,数据是通过流的方式上传的,而不是直接读取文件或数据进行上传,因此适用于上传大文件或者流数据NSURLSessionUploadTask *uploadTask = [self.session uploadTaskWithStreamedRequest:request];[self addDelegateForUploadTask:uploadTask progress:uploadProgressBlock completionHandler:completionHandler];return uploadTask;
}

uploadTaskWithRequest根据不同的数据创建一个NSURLSessionUploadTask任务,最终都会走到AFURLSessionManageraddDelegateForUploadTask为对应的uploadTask设置代理;
请添加图片描述
解析:

/// uploadTask:要添加代理的上传任务。
/// uploadProgressBlock:上传进度回调,通过该回调可以获取上传的进度信息。
/// completionHandler:上传完成回调,包含上传的响应、响应数据和错误信息。
- (void)addDelegateForUploadTask:(NSURLSessionUploadTask *)uploadTaskprogress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlockcompletionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{/// 创建了一个AFURLSessionManagerTaskDelegate对象作为上传任务的代理,将该代理与上传任务关联AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:uploadTask];delegate.manager = self;delegate.completionHandler = completionHandler;/// 将上传任务的描述设置为AFURLSessionManager的taskDescriptionForSessionTasks属性。uploadTask.taskDescription = self.taskDescriptionForSessionTasks;/// 最后,将代理对象设置为上传任务的代理,并设置上传进度回调和上传完成回调[self setDelegate:delegate forTask:uploadTask];delegate.uploadProgressBlock = uploadProgressBlock;
}

downloadTaskWithRequest

/// 根据指定的请求创建downloadTask
// 参数:
/// request:下载请求,即要下载的资源地址。
/// downloadProgressBlock:下载进度回调,用于获取下载进度信息。
/// destination:下载目标回调,用于指定下载文件的存储位置。
/// completionHandler:下载完成回调,包含下载的响应、文件路径和错误信息。
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)requestprogress:(void (^)(NSProgress *downloadProgress)) downloadProgressBlockdestination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destinationcompletionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler
{/// 使用self.session创建一个NSURLSessionDownloadTask对象,即创建了一个下载任务。NSURLSessionDownloadTask *downloadTask = [self.session downloadTaskWithRequest:request];/// 调用addDelegateForDownloadTask:progress:destination:completionHandler:方法为下载任务添加代理[self addDelegateForDownloadTask:downloadTask progress:downloadProgressBlock destination:destination completionHandler:completionHandler];return downloadTask;
}

downloadTaskWithResumeData

///  创建重用数据的下载任务:根据已经下载的数据ResumeData创建下载任务继续进行下载
///  官方:用于创建一个带有断点续传功能的下载任务并添加相关的代理。// 参数
///  resumeData:包含了之前下载任务的断点续传数据,用于恢复之前的下载进度。
/// downloadProgressBlock:下载进度回调,用于获取下载进度信息。
/// destination:下载目标回调,用于指定下载文件的存储位置。
/// completionHandler:下载完成回调,包含下载的响应、文件路径和错误信息。
- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeDataprogress:(void (^)(NSProgress *downloadProgress)) downloadProgressBlockdestination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destinationcompletionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler
{/// 首先使用self.session和提供的断点续传数据resumeData创建一个NSURLSessionDownloadTask对象,即创建了一个带有断点续传功能的下载任务。NSURLSessionDownloadTask *downloadTask = [self.session downloadTaskWithResumeData:resumeData];/// 调用addDelegateForDownloadTask:progress:destination:completionHandler:方法为下载任务添加代理,并传入下载进度回调、目标回调和完成回调。[self addDelegateForDownloadTask:downloadTask progress:downloadProgressBlock destination:destination completionHandler:completionHandler];return downloadTask;
}

download最终也会调用addDelegateForDownloadTask

解析:

/// 该方法 用于为下载任务添加代理和相关的回
/// downloadTask:要添加代理的下载任务。
/// downloadProgressBlock:下载进度回调,用于获取下载进度信息。
/// destination:下载目标回调,用于指定下载文件的存储位置。
/// completionHandler:下载完成回调,包含下载的响应、文件路径和错误信息。、
- (void)addDelegateForDownloadTask:(NSURLSessionDownloadTask *)downloadTaskprogress:(void (^)(NSProgress *downloadProgress)) downloadProgressBlockdestination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destinationcompletionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler
{AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:downloadTask];delegate.manager = self;delegate.completionHandler = completionHandler;/// 如果提供了destination回调,则设置代理的downloadTaskDidFinishDownloading属性为一个代码块,该代码块接收NSURLSession、NSURLSessionDownloadTask和下载文件的临时位置作为参数,并通过调用destination回调来返回最终的下载文件位置if (destination) {delegate.downloadTaskDidFinishDownloading = ^NSURL * (NSURLSession * __unused session, NSURLSessionDownloadTask *task, NSURL *location) {return destination(location, task.response);};}/// 设置下载任务的taskDescription属性为self.taskDescriptionForSessionTasks,这是用于描述任务的字符串。downloadTask.taskDescription = self.taskDescriptionForSessionTasks;[self setDelegate:delegate forTask:downloadTask];delegate.downloadProgressBlock = downloadProgressBlock;
}

1.2.2 AFURLSessionMananger遵守的代理

在AFURLSessionMananger的实现文件里面可以发现NSURLSessionTaskDelegateNSURLSessionDataDelegate以及NSURLSessionDownloadDelegate

需要提前说明的是AFURLSessionManager对这些代理做了一些公共的处理,最终转发到自定义的代理AFURLSessionManagerTaskDelegate的3个代理方法中,用来负责把每个task对应的数据回调回去;

围绕他们三个展开学习
NSURLSessionDownloadDelegate

NSURLSessionDownloadDelegate的方法在AFURLSessionMananger实现了3个。

  • URLSession:downloadTask:didFinishDownloadingToURL:
    在下载任务完成后调用,提供下载文件的临时位置URL。可以在此方法中处理下载后的文件移动、保存等操作。
  • URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:
    在下载任务进行中定期调用,提供下载进度的相关信息,包括已写入数据大小和总数据大小。可以在此方法中更新下载进度条等UI元素。
  • URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes:
    在恢复下载任务时调用,提供已恢复的下载位置和预期的总字节数。
#pragma mark - NSURLSessionDownloadDelegate
/// 在下载任务完成后调用,提供下载文件的临时位置URL。可以在此方法中处理下载后的文件移动、保存等操作。
- (void)URLSession:(NSURLSession *)sessiondownloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
{
// 转发代理AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask];if (self.downloadTaskDidFinishDownloading) {NSURL *fileURL = self.downloadTaskDidFinishDownloading(session, downloadTask, location);if (fileURL) {delegate.downloadFileURL = fileURL;NSError *error = nil;if (![[NSFileManager defaultManager] moveItemAtURL:location toURL:fileURL error:&error]) {[[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDownloadTaskDidFailToMoveFileNotification object:downloadTask userInfo:error.userInfo];} else {[[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDownloadTaskDidMoveFileSuccessfullyNotification object:downloadTask userInfo:nil];}return;}}if (delegate) {[delegate URLSession:session downloadTask:downloadTask didFinishDownloadingToURL:location];}
}
/// 在下载任务进行中定期调用,提供下载进度的相关信息,包括已写入数据大小和总数据大小。可以在此方法中更新下载进度条等UI元素。
- (void)URLSession:(NSURLSession *)sessiondownloadTask:(NSURLSessionDownloadTask *)downloadTaskdidWriteData:(int64_t)bytesWrittentotalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{// 转发代理AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask];if (delegate) {[delegate URLSession:session downloadTask:downloadTask didWriteData:bytesWritten totalBytesWritten:totalBytesWritten totalBytesExpectedToWrite:totalBytesExpectedToWrite];}if (self.downloadTaskDidWriteData) {self.downloadTaskDidWriteData(session, downloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);}
}
/// 在恢复下载任务时调用,提供已恢复的下载位置和预期的总字节数
- (void)URLSession:(NSURLSession *)sessiondownloadTask:(NSURLSessionDownloadTask *)downloadTaskdidResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes
{// // 转发代理AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask];if (delegate) {[delegate URLSession:session downloadTask:downloadTask didResumeAtOffset:fileOffset expectedTotalBytes:expectedTotalBytes];}if (self.downloadTaskDidResume) {self.downloadTaskDidResume(session, downloadTask, fileOffset, expectedTotalBytes);}
}

这三个代理方法最终都会进行代理转发,到AFURLSessionManagerTaskDelegate中,AF中的deleagate是需要对应每个task去私有化处理的对应看看AFURLSessionManagerTaskDelegate中的这三个代理方法都做了什么 吧:

ps:别跳转错了
请添加图片描述

#pragma mark - NSURLSessionDownloadDelegate- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTaskdidWriteData:(int64_t)bytesWrittentotalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{// 更新当前下载进度self.downloadProgress.totalUnitCount = totalBytesExpectedToWrite;self.downloadProgress.completedUnitCount = totalBytesWritten;
}- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTaskdidResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes{// 更新当前下载进度self.downloadProgress.totalUnitCount = expectedTotalBytes;self.downloadProgress.completedUnitCount = fileOffset;
}
/// ‼️下载完成调用
- (void)URLSession:(NSURLSession *)sessiondownloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
{self.downloadFileURL = nil;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];}}}
}
  • 在 ‼️ 下载完成时的调用代理方法中,AFURLSessionManagerAFURLSessionManagerTaskDelegate中都进行了文件路径的移动,而NSURlSession代理的下载路径是所有request公用的下载路径,设置之后所有的request都会下载到之前的那个路径。而AFURLSessionManagerTaskDelegate中对应到每一个task中,每一个task可以设置自己的下载路径;
  • 总结:这些代理方法在AFURLSessionManager中实现的时候都是对session做一个公共的处理,每一个不同的task进行特定的处理时,需要将代理转发到AFURLSessionManagerTaskDelegate中,在AFURLSessionManagerTaskDelegate的代理中实现;

1.3 AFURLSessionManagerTaskDelegate的作用

AFURLSessionManagerTaskDelegate 是 AFNetworking 框架中的一个类,用于处理 URLSessionTask 相关的代理回调。它作为 AFURLSessionManager 的任务代理,负责处理网络请求任务的进度、完成回调等操作。

具体来说,AFURLSessionManagerTaskDelegate 的主要作用包括:

  • 处理任务进度:通过设置 uploadProgressBlock 和 downloadProgressBlock 属性,可以监控上传任务和下载任务的进度,并在进度发生变化时执行相应的代码块。
  • 处理任务完成回调:在任务完成时,会执行 completionHandler 属性所指定的代码块,将任务的响应、响应数据和错误信息传递给回调函数,以便进一步处理任务的结果。
  • 处理下载任务的文件保存路径:对于下载任务,可以通过设置 downloadTaskDidFinishDownloading 属性,来指定任务完成后将文件保存的路径。
  • 管理任务与代理的关系:在创建任务时,会将任务与对应的 AFURLSessionManagerTaskDelegate 对象关联起来,以确保任务的代理回调能够正确处理。
  • 总的来说,AFURLSessionManagerTaskDelegate 扮演了一个中间角色,连接了 URLSessionTask 和 AFURLSessionManager 之间的交互,处理任务的进度、完成回调和其他相关操作,提供了更便捷的方式来管理和处理网络请求任务。

2. AFHTTPSessionManager

AFHTTPSessionManager本身是对网络请求做了一些简单的封装,请求的整个逻辑是分发给AFURLSessionManager或者其他类去做的;其内部管理自己的两种序列化工具,用来对请求和响应的数据做序列化;同时依赖于父类提供的保证安全,监控网络状态,实现发出HTTP请求的核心功能;

2.1 属性和接口

在这里插入图片描述
其实上一章已经很详细的说明了很多AFHTTPSessionManager的内容

AFHTTPSessionManager的一些方法的实现,初始化方法最终都会调用到AFURLSessionManager中的初始化方法完成sessionManager的初始化;

GET为例:

- (NSURLSessionDataTask *)GET:(NSString *)URLStringparameters:(nullable id)parametersheaders:(nullable NSDictionary <NSString *, NSString *> *)headersprogress:(nullable void (^)(NSProgress * _Nonnull))downloadProgresssuccess:(nullable void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))successfailure:(nullable void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure
{/// 调用 dataTaskWithHTTPMethod:URLString:parameters:headers:uploadProgress:downloadProgress:success:failure: 方法,该方法创建一个 NSURLSessionDataTask 数据任务对象,用于执行指定的 HTTP GET 请求。将传入的参数传递给该方法以构建请求。NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"GET"URLString:URLStringparameters:parametersheaders:headersuploadProgress:nildownloadProgress:downloadProgresssuccess:successfailure:failure];/// 调用 [dataTask resume] 方法启动数据任务,使其开始执行。[dataTask resume];/// 返回数据任务对象 dataTask。return dataTask;
参数:
URLString:请求的URL值
parameters:根据需求的请求参数
headers:请求头
downloadProgress:更新下载进度的对象
success:任务成功后执行的Block对象
failure:任务失败后执行的Block对象
}

一是生成一个dataTask任务,二是调用resume开启请求;

该类的核心方法dataTaskWithHTTPMethod:URLString:parameters:headers:uploadProgress:downloadProgress:success:failure: 该方法是生成datatask,是AFHTTPSessionManager中的da taTaskWithHTTPMethod方法

在上一章也讲过! 很重要!

该方法做了两件事情:一是对请求参数进行序列化;二是调用dataTaskWithRequest方法生成后一个datatask任务;最终返回一个datatask;

- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)methodURLString:(NSString *)URLStringparameters:(nullable id)parametersheaders:(nullable NSDictionary <NSString *, NSString *> *)headersuploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressdownloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgresssuccess:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))successfailure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure
{NSError *serializationError = nil;/// 使用 `self.requestSerializer` 对象根据传入的参数构建一个 `NSMutableURLRequest` 可变请求对象。/// self.requestSerializer:请求序列化器/// ‼️‼️ 需要点进去的方法1NSMutableURLRequest *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:` 方法来配置任务的上传进度回调、下载进度回调和完成处理程序块。// ‼️ 需要点进去的方法2dataTask = [self dataTaskWithRequest:requestuploadProgress:uploadProgressdownloadProgress:downloadProgresscompletionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {if (error) {if (failure) {failure(dataTask, error);}} else {if (success) {success(dataTask, responseObject);}}}];return dataTask;

总结

到此,网络通讯模块所做的事情就到此,在该模块中主要的任务就是发起网络请求。分成AFURLSessionManger和 AFHTTPSessionManager两部分来做处理。 AFURLSessionManger是AFHTTPSessionManager的父类,其中AFURLSessionManger内部还包含AFURLSessionManagerTaskDelegate和_AFURLSessionTaskSwizzling;AFHTTPSessionManager本身是对网络请求做了一些简单的封装,请求的整个逻辑是分发给AFURLSessionManager或者其他类去做的;其内部管理自己的两种序列化工具,用来对请求和响应的数据做序列化;同时依赖于父类提供的保证安全,监控网络状态,实现发出HTTP请求的核心功能;

参考:AFN源码解析

相关文章:

【AFNetWorking源码(二)AFURLSessionManger和AFHTTPSessionManager】

前言 学习了Mananger的初始化和以GET请求为例的过程&#xff0c;发现整个过程离不开AFHTTPSessionManager和AFURLSessionManger的某些方法。这两个是AFN的重要的网络通信模块内容&#xff0c;对它们作揖详细的学习。 AFURLSessionManager和AFHTTPSessionManager都是AFNetwork…...

编程不头秃,Google「AI程序员」来了,聊天就能敲代码

上周 Google 在 I/O 大会宣布了一个能够辅助编程的聊天机器人 Codey&#xff0c;现在它终于上线 Google Colab 啦&#xff01; &#x1f31f; Codey 是基于 Google 目前最新的大语言模型 PaLM 2 运行&#xff0c;有着强大的语言理解和编程能力。 Codey 有这些功能&#xff1…...

【数据结构与算法】基础数据结构

文章目录 数组概述动态数组二维数组局部性原理越界检查 链表概述单向链表单向链表&#xff08;带哨兵&#xff09;双向链表&#xff08;带哨兵&#xff09;环形链表&#xff08;带哨兵&#xff09; 队列概述链表实现环形数组实现 栈概述链表实现数组实现应用 双端队列概述链表实…...

k8s系列(四)——资源对象

k8s系列四——资源对象 pod概念 思考&#xff1a;为什么k8s会引出pod这个概念&#xff0c;容器不能解决么&#xff1f; 我的理解&#xff1a;一组密切相关的服务使用容器的话&#xff0c;如果他们的镜像不在一个容器里的话&#xff0c;那么就需要配置反向代理进行通信&#xf…...

JavaScript如何使用for循环

JavaScript 是一门非常有趣的编程语言&#xff0c;它可以让我们在浏览器中创建交互式的 Web 应用程序。在 JavaScript 中&#xff0c;我们可以使用 for 循环来迭代一个数组或对象&#xff0c;从而执行一系列的操作。下面是一些关于 for 循环的有趣的用法和例子。 为什么要使用…...

(浙大陈越版)数据结构 第三章 树(上) 3.1 树和树的表示

目录 3.1.1 引子&#xff08;顺序查找&#xff09; 什么是树 查找 3.1.2 引子 二分查找例子(BinarySearch) 二分查找 3.1.3 引子 二分查找实现 二分查找代码 二分查找的启示 3.1.4 树的定义 一些基本术语&#xff1a; 3.1.5 树的表示 3.1.1 引子&#xff08;顺序查找…...

平抑风电波动的电-氢混合储能容量优化配置(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

#机器学习--重新看待线性回归

#机器学习--重新看待线性回归 引言普通视角的线性回归最大似然角度的线性回归总结 引言 本系列博客旨在为机器学习(深度学习)提供数学理论基础。因此内容更为精简&#xff0c;适合二次学习的读者快速学习或查阅。 普通视角的线性回归 对于一组数据 { ( x 0 , y 0 ) , … ( x m…...

亚马逊,shopee,lazada卖家如何组建自己的测评团队

测评补单&#xff0c;这个话题在如今不管国内还是国外的电商行业已经是众所周知&#xff0c;它能够快速帮助自己的产品添加评论&#xff0c;获取排名&#xff0c;打造爆款&#xff0c;可以让用户更加真实、清晰、快捷的了解产品&#xff0c;以及产品的使用&#xff0c;快速上手…...

flink cdc 用mybatis-plus写到mysql5.6

背景 项目中需要做一个数据同步的功能, 在方案对比中,canal 与flink cdc 都有尝试。 起初在网上找的flink例子,要么只能支持mysql5.7以上版本,要么就是需要序列化各种bug,比如就不能直接使用 @Autowired xxxServer 来调用数据库层面的注入,getBaseMapper()为空 因为目…...

【C++】模板的一点简单介绍

模板 前言泛型编程函数模板概念格式函数模板的原理函数模板的实例化 类模板类模板的定义格式类模板的实例化 前言 这篇博客讲的是模板的一些基本知识&#xff0c;并没有那么深入&#xff0c;但是如果你是为了过期末考试而搜的这篇博客&#xff0c;我觉得下面讲的是够了的。 之…...

SpringCloud概述

前言 什么是微服务&#xff1f; ​ 微服务是一种面向服务的架构(SOA)风格&#xff0c;其中&#xff0c;应用程序被构建为多个不同的小型服务的集合而不是单个应用程序。与单个程序不同的是&#xff0c;微服务让你可以同时运行多个独立的应用程序&#xff0c;而这些独立的应用…...

Metal入门学习:GPU并行计算大数组相加

一、编程指南PDF下载链接(中英文档&#xff09; 1、Metal编程指南PDF链接 https://github.com/dennie-lee/ios_tech_record/raw/main/Metal学习PDF/Metal 编程指南.pdf 2、Metal着色语言(Metal Shader Language:简称MSL)编程指南PDF链接 https://github.com/dennie-lee/ios_te…...

关于在spyder,jupyter notebook下创建虚拟环境(pytorch,tensorflow)均有效

anaconda下载地址 https://www.anaconda.com/download/ 下载完成后打开anaconda目录下的 anaconda prompt 在命令行中输入下面的命令创建一个叫tf2.0的虚拟环境&#xff08;“tf2.0”是建立的Conda虚拟环境的名字&#xff0c;可以自拟&#xff09; conda create -n tf2.0 p…...

oracle 闪回恢复

oracle 闪回恢复 闪回恢复区主要通过3个初始化参数来设置和管理&#xff1a; db_recovery_file_dest&#xff1a;指定闪回恢复区的位置 db_recovery_file_dest_size&#xff1a;指定闪回恢复区的可用空间大小 db_flashback_retention_target&#xff1a;指定数据库可以回退的时…...

LeetCode 322 零钱兑换

题目&#xff1a; 给你一个整数数组 coins &#xff0c;表示不同面额的硬币&#xff1b;以及一个整数 amount &#xff0c;表示总金额。计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额&#xff0c;返回 -1 。你可以认为每种硬币的数量…...

面试篇SpringMVC是什么以及工作原理

1&#xff0c;什么是SpringMVC呢&#xff1f; 它是Spring的一种设计模式&#xff0c;一款框架。 2&#xff0c;MVC分别代表什么&#xff1f; M代表模型即model的缩写&#xff0c;指业务逻辑层模型。V代表视图即View的缩写&#xff0c;指视图层。C则是controller的缩写&#xff…...

jQuery-层级选择器

<!DOCTYPE HTML> <html> <head> <meta http-equiv"Content-Type" content"text/html; charsetUTF-8"> <title>层级选择器</title> <style type"text/css"> …...

【Java数据结构】——第十节(下).选择排序与堆排序

作者简介&#xff1a;大家好&#xff0c;我是未央&#xff1b; 博客首页&#xff1a;未央.303 系列专栏&#xff1a;Java初阶数据结构 每日一句&#xff1a;人的一生&#xff0c;可以有所作为的时机只有一次&#xff0c;那就是现在&#xff01;&#xff01;&#xff01; 文章目…...

45道SQL题目陆续更新

文章目录 学习视频配置环境第一天内连接 外连接第二天第三天 学习视频 学习视频 配置环境 四张表 配置四张表的sql语句 #创建发据库 create database frogdata charsetutf8&#xff1b;use frogdata;# 学生表 Student create table Student( SId varchar(10), Sname var…...

谷歌浏览器插件

项目中有时候会用到插件 sync-cookie-extension1.0.0&#xff1a;开发环境同步测试 cookie 至 localhost&#xff0c;便于本地请求服务携带 cookie 参考地址&#xff1a;https://juejin.cn/post/7139354571712757767 里面有源码下载下来&#xff0c;加在到扩展即可使用FeHelp…...

大数据学习栈记——Neo4j的安装与使用

本文介绍图数据库Neofj的安装与使用&#xff0c;操作系统&#xff1a;Ubuntu24.04&#xff0c;Neofj版本&#xff1a;2025.04.0。 Apt安装 Neofj可以进行官网安装&#xff1a;Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

java 实现excel文件转pdf | 无水印 | 无限制

文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析

这门怎么题库答案不全啊日 来简单学一下子来 一、选择题&#xff08;可多选&#xff09; 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘&#xff1a;专注于发现数据中…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat&#xff08;I/O Statistics&#xff09;是Linux系统下用于监视系统输入输出设备和CPU使…...

376. Wiggle Subsequence

376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

GC1808高性能24位立体声音频ADC芯片解析

1. 芯片概述 GC1808是一款24位立体声音频模数转换器&#xff08;ADC&#xff09;&#xff0c;支持8kHz~96kHz采样率&#xff0c;集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器&#xff0c;适用于高保真音频采集场景。 2. 核心特性 高精度&#xff1a;24位分辨率&#xff0c…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)

前言&#xff1a; 在Java编程中&#xff0c;类的生命周期是指类从被加载到内存中开始&#xff0c;到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期&#xff0c;让读者对此有深刻印象。 目录 ​…...

STM32---外部32.768K晶振(LSE)无法起振问题

晶振是否起振主要就检查两个1、晶振与MCU是否兼容&#xff1b;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容&#xff08;CL&#xff09;与匹配电容&#xff08;CL1、CL2&#xff09;的关系 2. 如何选择 CL1 和 CL…...

论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing

Muffin 论文 现有方法 CRADLE 和 LEMON&#xff0c;依赖模型推理阶段输出进行差分测试&#xff0c;但在训练阶段是不可行的&#xff0c;因为训练阶段直到最后才有固定输出&#xff0c;中间过程是不断变化的。API 库覆盖低&#xff0c;因为各个 API 都是在各种具体场景下使用。…...