【AFNetWorking源码(二)AFURLSessionManger和AFHTTPSessionManager】
前言
学习了Mananger的初始化和以GET请求为例的过程,发现整个过程离不开AFHTTPSessionManager和AFURLSessionManger的某些方法。这两个是AFN的重要的网络通信模块内容,对它们作揖详细的学习。
AFURLSessionManager
和AFHTTPSessionManager
都是AFNetworking
库中的两个类,用于处理网络请求和会话管理
如果只涉及到HTTP请求,一般会直接使用AFHTTPSessionManager
进行操作。而AFURLSessionManager
则提供了更底层的接口,适用于特定的定制需求或与NSURLSession
相关的操作
1.1 AFURLSessionManger和AFHTTPSessionManager的关系
图解
首先AFURLSessionManger
是AFHTTPSessionManager
的父类,其中AFURLSessionManger
内部还包含AFURLSessionManagerTaskDelegate
和_AFURLSessionTaskSwizzling
;
AFHTTPSessionManager
本身是对网络请求做了一些简单的封装,请求的整个逻辑是分发给AFURLSessionManager或者其他类去做的;其内部管理自己的两种序列化工具,用来对请求和响应的数据做序列化;同时依赖于父类提供的保证安全,监控网络状态,实现发出HTTP请求的核心功能;
AFHTTPSessionManager
也可以是AFURLSessionManager
的基础上进一步封装,专门用于处理基于HTTP协议的网络请求,提供了更方便的HTTP请求方法和相关功能,如GET、POST等常见的HTTP方法,以及请求参数的设置、请求头的配置、数据解析等功能
1.2 AFURLSessionManager
1.2.1 AFURLSessionManger功能
AFURLSessionManager
负责生成对应的NSURLSession
的实例,管理AFNetworkReachabilityManager
和AFSecurityPolicy
,以此一来查看网络的连接情况,二来保证请求的安全,同时初始化生成一个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的实现文件里面可以发现NSURLSessionTaskDelegate
,NSURLSessionDataDelegate
以及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];}}}
}
- 在 ‼️ 下载完成时的调用代理方法中,
AFURLSessionManager
和AFURLSessionManagerTaskDelegate
中都进行了文件路径的移动,而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请求为例的过程,发现整个过程离不开AFHTTPSessionManager和AFURLSessionManger的某些方法。这两个是AFN的重要的网络通信模块内容,对它们作揖详细的学习。 AFURLSessionManager和AFHTTPSessionManager都是AFNetwork…...

编程不头秃,Google「AI程序员」来了,聊天就能敲代码
上周 Google 在 I/O 大会宣布了一个能够辅助编程的聊天机器人 Codey,现在它终于上线 Google Colab 啦! 🌟 Codey 是基于 Google 目前最新的大语言模型 PaLM 2 运行,有着强大的语言理解和编程能力。 Codey 有这些功能࿱…...

【数据结构与算法】基础数据结构
文章目录 数组概述动态数组二维数组局部性原理越界检查 链表概述单向链表单向链表(带哨兵)双向链表(带哨兵)环形链表(带哨兵) 队列概述链表实现环形数组实现 栈概述链表实现数组实现应用 双端队列概述链表实…...

k8s系列(四)——资源对象
k8s系列四——资源对象 pod概念 思考:为什么k8s会引出pod这个概念,容器不能解决么? 我的理解:一组密切相关的服务使用容器的话,如果他们的镜像不在一个容器里的话,那么就需要配置反向代理进行通信…...
JavaScript如何使用for循环
JavaScript 是一门非常有趣的编程语言,它可以让我们在浏览器中创建交互式的 Web 应用程序。在 JavaScript 中,我们可以使用 for 循环来迭代一个数组或对象,从而执行一系列的操作。下面是一些关于 for 循环的有趣的用法和例子。 为什么要使用…...

(浙大陈越版)数据结构 第三章 树(上) 3.1 树和树的表示
目录 3.1.1 引子(顺序查找) 什么是树 查找 3.1.2 引子 二分查找例子(BinarySearch) 二分查找 3.1.3 引子 二分查找实现 二分查找代码 二分查找的启示 3.1.4 树的定义 一些基本术语: 3.1.5 树的表示 3.1.1 引子(顺序查找…...

平抑风电波动的电-氢混合储能容量优化配置(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
#机器学习--重新看待线性回归
#机器学习--重新看待线性回归 引言普通视角的线性回归最大似然角度的线性回归总结 引言 本系列博客旨在为机器学习(深度学习)提供数学理论基础。因此内容更为精简,适合二次学习的读者快速学习或查阅。 普通视角的线性回归 对于一组数据 { ( x 0 , y 0 ) , … ( x m…...

亚马逊,shopee,lazada卖家如何组建自己的测评团队
测评补单,这个话题在如今不管国内还是国外的电商行业已经是众所周知,它能够快速帮助自己的产品添加评论,获取排名,打造爆款,可以让用户更加真实、清晰、快捷的了解产品,以及产品的使用,快速上手…...
flink cdc 用mybatis-plus写到mysql5.6
背景 项目中需要做一个数据同步的功能, 在方案对比中,canal 与flink cdc 都有尝试。 起初在网上找的flink例子,要么只能支持mysql5.7以上版本,要么就是需要序列化各种bug,比如就不能直接使用 @Autowired xxxServer 来调用数据库层面的注入,getBaseMapper()为空 因为目…...

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

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

Metal入门学习:GPU并行计算大数组相加
一、编程指南PDF下载链接(中英文档) 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的虚拟环境(“tf2.0”是建立的Conda虚拟环境的名字,可以自拟) conda create -n tf2.0 p…...

oracle 闪回恢复
oracle 闪回恢复 闪回恢复区主要通过3个初始化参数来设置和管理: db_recovery_file_dest:指定闪回恢复区的位置 db_recovery_file_dest_size:指定闪回恢复区的可用空间大小 db_flashback_retention_target:指定数据库可以回退的时…...
LeetCode 322 零钱兑换
题目: 给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。你可以认为每种硬币的数量…...
面试篇SpringMVC是什么以及工作原理
1,什么是SpringMVC呢? 它是Spring的一种设计模式,一款框架。 2,MVC分别代表什么? M代表模型即model的缩写,指业务逻辑层模型。V代表视图即View的缩写,指视图层。C则是controller的缩写ÿ…...

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

【Java数据结构】——第十节(下).选择排序与堆排序
作者简介:大家好,我是未央; 博客首页:未央.303 系列专栏:Java初阶数据结构 每日一句:人的一生,可以有所作为的时机只有一次,那就是现在!!! 文章目…...

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

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...

iview框架主题色的应用
1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题,无需引入,直接可…...

认识CMake并使用CMake构建自己的第一个项目
1.CMake的作用和优势 跨平台支持:CMake支持多种操作系统和编译器,使用同一份构建配置可以在不同的环境中使用 简化配置:通过CMakeLists.txt文件,用户可以定义项目结构、依赖项、编译选项等,无需手动编写复杂的构建脚本…...
前端高频面试题2:浏览器/计算机网络
本专栏相关链接 前端高频面试题1:HTML/CSS 前端高频面试题2:浏览器/计算机网络 前端高频面试题3:JavaScript 1.什么是强缓存、协商缓存? 强缓存: 当浏览器请求资源时,首先检查本地缓存是否命中。如果命…...

聚六亚甲基单胍盐酸盐市场深度解析:现状、挑战与机遇
根据 QYResearch 发布的市场报告显示,全球市场规模预计在 2031 年达到 9848 万美元,2025 - 2031 年期间年复合增长率(CAGR)为 3.7%。在竞争格局上,市场集中度较高,2024 年全球前十强厂商占据约 74.0% 的市场…...
shell脚本质数判断
shell脚本质数判断 shell输入一个正整数,判断是否为质数(素数)shell求1-100内的质数shell求给定数组输出其中的质数 shell输入一个正整数,判断是否为质数(素数) 思路: 1:1 2:1 2 3:1 2 3 4:1 2 3 4 5:1 2 3 4 5-------> 3:2 4:2 3 5:2 3…...