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

iOS开发-NSOperationQueue实现上传图片队列

iOS开发-NSOperationQueue实现上传图片队列

在开发中,遇到发帖需要上传图片,需要上传队列,这时候用到了NSOperationQueue

一、NSOperation与NSOperationQueue

  • 什么NSOperation

NSOperation为控制任务状态、优先级、依赖关系以及任务管理提供了一种线程安全的结构。可以通过调用start方法来手动启动一个任务,或者把它加入到NSOperationQueue中,当它到达队列头部时自动启动。

  • NSOperation的三个执行状态

    • isReady、
    • isExecuting、
    • isFinished

这三个是NSOperation生命周期中的三个互斥的状态。

二、通过NSOperationQueue添加NSOperation

NSOperationQueue,

self.operationQueue = [[NSOperationQueue alloc] init];
[self.operationQueue setMaxConcurrentOperationCount:1];

在NSOperationQueue添加一系列的NSOperation,addDependency会使当前的NSOperation依赖上一个NSOperation完成后执行相应的block操作。

NSOperation *operation = [[NSOperation alloc] init];[self.operationQueue addOperation:operation];for (NSInteger index = 0; index < self.files.count; index++) {NSBlockOperation *theOperation  = [NSBlockOperation blockOperationWithBlock:^{[self uploadFileOperation:index];}];[theOperation addDependency:operation];[self.operationQueue addOperation:theOperation];operation = theOperation;}

三、实现上传功能

针对每一个上传的文件定义对应的文件model

SDUpFileModel.h

#import <Foundation/Foundation.h>typedef NS_ENUM(NSInteger, SDUpFileType) {SDUpFileTypeImage = 0,  //上传的图片类型SDUpFileTypeVoice,      //上传的音频类型SDUpFileTypeVideo       //上传的视频类型
};/**上传的资源类型model,image,voice,video*/
@interface SDUpFileModel : NSObject/**上传的文件类型*/
@property (nonatomic, assign) SDUpFileType fileType;/**上传到七牛的key*/
@property (nonatomic, strong) NSString *key;/**上传所需要的token,七牛的token*/
@property (strong, nonatomic) NSString *token;/**上传的filePath,文件本地路径*/
@property (nonatomic, strong) NSString *filePath;/**上传所需要的参数,视频参数,图片参数,语音参数等,根据fileType,参数不一样*/
@property (nonatomic, strong) NSDictionary *params;@end

SDUpFileModel.m

#import "SDUpFileModel.h"@implementation SDUpFileModel@end

上传的功能使用AFNetworking上传功能

NSURL *url = [NSURL URLWithString:kQiniuUpHost];AFHTTPSessionManager *operationManager = [[AFHTTPSessionManager alloc] initWithBaseURL:url];NSMutableDictionary *parameters = [NSMutableDictionary dictionaryWithObjectsAndKeys:theFile.token,@"token",kQiniuUserAgent,@"User-Agent",nil];if (theFile.key){[parameters setObject:theFile.key forKey:@"key"];[parameters setObject:url forKey:theFile.key];}if (theFile.params){for (NSString *key in theFile.params){[parameters setObject:[theFile.params objectForKey:key] forKey:key];}}NSMutableURLRequest *request = [operationManager.requestSerializer multipartFormRequestWithMethod:@"POST" URLString:kQiniuUpHost parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {if (theFile.fileType == SDUpFileTypeImage) {//上传图片文件[formData appendPartWithFileURL:[NSURL fileURLWithPath:theFile.filePath] name:@"file" fileName:@"file" mimeType:@"image/jpeg" error:nil];} else if (theFile.fileType == SDUpFileTypeVoice) {//语音文件[formData appendPartWithFileURL:[NSURL fileURLWithPath:theFile.filePath] name:@"file" fileName:@"file" mimeType:@"audio/amr" error:nil];} else if (theFile.fileType == SDUpFileTypeVideo) {//mp4视频文件[formData appendPartWithFileURL:[NSURL fileURLWithPath:theFile.filePath] name:@"file" fileName:@"file" mimeType:@"video/mpeg4" error:nil];}} error:nil];__block NSURLSessionUploadTask *task = nil;task = [operationManager uploadTaskWithStreamedRequest:request progress:^(NSProgress * _Nonnull uploadProgress) {float percent = uploadProgress.completedUnitCount * 1.0 / uploadProgress.totalUnitCount;if (self.upProgressHandler) {self.upProgressHandler(theFile, percent);}} completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {NSHTTPURLResponse *taskresponse = (NSHTTPURLResponse *)task.response;if(error == nil) {NSInteger statusCode = taskresponse.statusCode;if (statusCode == 200){if (index == self.files.count -1) {if (self.upAllComplectionHandler) {self.upAllComplectionHandler(self);}}} else{if (self.upFilesFailedHandler) {self.upFilesFailedHandler(self);}[self cancelAllUploadTask];}}else {NSString *errorStr = [responseObject objectForKey:@"error"];if ([errorStr isEqualToString:@"expired token"]) {if (self.upFilesTokenErrorHandler) {self.upFilesTokenErrorHandler(self);}} else {if (self.upFilesFailedHandler) {self.upFilesFailedHandler(self);}}[self cancelAllUploadTask];}}];[task resume];

上传工具的完整代码如下

SDUploaderTool.h

#import <Foundation/Foundation.h>
#import "SDUpFileModel.h"@class SDUploaderTool;/**上传单个文件进度的block*/
typedef void (^UploadProgressHandler)(SDUpFileModel *fileModel, float percent);/**上传所有文件成功的block*/
typedef void (^UploadAllCompletionHandler)(SDUploaderTool *uploader);/**上传文件失败的block,上传文件的token异常,重新上传,重试3次*/
typedef void (^UploadFilesTokenErrorHandler)(SDUploaderTool *uploader);/**上传文件失败的block*/
typedef void (^UploadFilesFailedHandler)(SDUploaderTool *uploader);@interface SDUploaderTool : NSObject/**上传单个文件进度的block*/
@property (nonatomic, copy) UploadProgressHandler upProgressHandler;/**上传所有文件成功的block*/
@property (nonatomic, copy) UploadAllCompletionHandler upAllComplectionHandler;/**上传文件失败的block,上传文件的token异常,重新上传,重试3次*/
@property (nonatomic, copy) UploadFilesTokenErrorHandler upFilesTokenErrorHandler;/**上传文件失败的block*/
@property (nonatomic, copy) UploadFilesFailedHandler upFilesFailedHandler;/**上传的资源列表,其中存储的是SDUpFileModel的对象*/
@property (nonatomic, strong) NSMutableArray *files;/**添加上传文件@param file SDUpFileModel*/
- (void)addFile:(SDUpFileModel *)file;/**添加多个上传文件@param theFiles 文件列表*/
- (void)addFiles:(NSArray *)theFiles;/**开始上传,启动上传*/
- (void)startUpload;/**取消所有的上传请求*/
- (void)cancelAllUploadTask;@end

SDUploaderTool.m

#import "SDUploaderTool.h"
#import <AFNetworking.h>#define kQiniuUpHost @"http://up.qiniu.com"
#define kQiniuUndefinedKey @"?"
#define kQiniuUserAgent  @"qiniu-ios-sdk"@interface SDUploaderTool ()@property (nonatomic, strong) NSOperationQueue *operationQueue;@end@implementation SDUploaderTool- (instancetype)init
{self = [super init];if (self) {self.files = [[NSMutableArray alloc] init];self.operationQueue = [[NSOperationQueue alloc] init];[self.operationQueue setMaxConcurrentOperationCount:1];}return self;
}/**添加上传文件@param file SDUpFileModel*/
- (void)addFile:(SDUpFileModel *)file {[self.files addObject:file];
}/**添加多个上传文件@param theFiles 文件列表*/
- (void)addFiles:(NSArray *)theFiles {[self.files addObjectsFromArray:theFiles];
}/**开始上传,启动上传*/
- (void)startUpload {if (!(self.files && self.files.count > 0)) {return;}NSOperation *operation = [[NSOperation alloc] init];[self.operationQueue addOperation:operation];for (NSInteger index = 0; index < self.files.count; index++) {NSBlockOperation *theOperation  = [NSBlockOperation blockOperationWithBlock:^{[self uploadFileOperation:index];}];[theOperation addDependency:operation];[self.operationQueue addOperation:theOperation];operation = theOperation;}
}/**取消所有的上传请求*/
- (void)cancelAllUploadTask {[self.operationQueue cancelAllOperations];
}/**执行上传,使用AFNetWorking@param index index*/
- (void)uploadFileOperation:(NSInteger)index {SDUpFileModel *theFile = self.files[index];NSURL *url = [NSURL URLWithString:kQiniuUpHost];AFHTTPSessionManager *operationManager = [[AFHTTPSessionManager alloc] initWithBaseURL:url];NSMutableDictionary *parameters = [NSMutableDictionary dictionaryWithObjectsAndKeys:theFile.token,@"token",kQiniuUserAgent,@"User-Agent",nil];if (theFile.key){[parameters setObject:theFile.key forKey:@"key"];[parameters setObject:url forKey:theFile.key];}if (theFile.params){for (NSString *key in theFile.params){[parameters setObject:[theFile.params objectForKey:key] forKey:key];}}NSMutableURLRequest *request = [operationManager.requestSerializer multipartFormRequestWithMethod:@"POST" URLString:kQiniuUpHost parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {if (theFile.fileType == SDUpFileTypeImage) {//上传图片文件[formData appendPartWithFileURL:[NSURL fileURLWithPath:theFile.filePath] name:@"file" fileName:@"file" mimeType:@"image/jpeg" error:nil];} else if (theFile.fileType == SDUpFileTypeVoice) {//语音文件[formData appendPartWithFileURL:[NSURL fileURLWithPath:theFile.filePath] name:@"file" fileName:@"file" mimeType:@"audio/amr" error:nil];} else if (theFile.fileType == SDUpFileTypeVideo) {//mp4视频文件[formData appendPartWithFileURL:[NSURL fileURLWithPath:theFile.filePath] name:@"file" fileName:@"file" mimeType:@"video/mpeg4" error:nil];}} error:nil];__block NSURLSessionUploadTask *task = nil;task = [operationManager uploadTaskWithStreamedRequest:request progress:^(NSProgress * _Nonnull uploadProgress) {float percent = uploadProgress.completedUnitCount * 1.0 / uploadProgress.totalUnitCount;if (self.upProgressHandler) {self.upProgressHandler(theFile, percent);}} completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {NSHTTPURLResponse *taskresponse = (NSHTTPURLResponse *)task.response;if(error == nil) {NSInteger statusCode = taskresponse.statusCode;if (statusCode == 200){if (index == self.files.count -1) {if (self.upAllComplectionHandler) {self.upAllComplectionHandler(self);}}} else{if (self.upFilesFailedHandler) {self.upFilesFailedHandler(self);}[self cancelAllUploadTask];}}else {NSString *errorStr = [responseObject objectForKey:@"error"];if ([errorStr isEqualToString:@"expired token"]) {if (self.upFilesTokenErrorHandler) {self.upFilesTokenErrorHandler(self);}} else {if (self.upFilesFailedHandler) {self.upFilesFailedHandler(self);}}[self cancelAllUploadTask];}}];[task resume];
}/**释放*/
- (void)dealloc {self.files = nil;[self.operationQueue cancelAllOperations];self.operationQueue = nil;
}@end

四、小结

iOS开发-NSOperationQueue实现上传图片队列。使用NSOperationQueue,NSOperation,通过AFnetworking上传功能实现。

学习记录,每天不停进步。

相关文章:

iOS开发-NSOperationQueue实现上传图片队列

iOS开发-NSOperationQueue实现上传图片队列 在开发中&#xff0c;遇到发帖需要上传图片&#xff0c;需要上传队列&#xff0c;这时候用到了NSOperationQueue 一、NSOperation与NSOperationQueue 什么NSOperation NSOperation为控制任务状态、优先级、依赖关系以及任务管理提…...

通过 CCIP 构建跨链应用(5 个案例)

Chainlink 的跨链互操作性协议&#xff08;CCIP&#xff09;是一种新的通用跨链通信协议&#xff0c;为智能合约开发人员提供了以最小化信任的方式在区块链网络之间传输数据和通证的能力。 目前&#xff0c;部署在多个区块链上的应用程序面临着资产、流动性和用户的碎片化问题…...

基于 yolov8 的人体姿态评估

写在前面 工作中遇到&#xff0c;简单整理博文内容为使用预训练模型的一个预测 Demo测试图片来源与网络,如有侵权请告知理解不足小伙伴帮忙指正 对每个人而言&#xff0c;真正的职责只有一个&#xff1a;找到自我。然后在心中坚守其一生&#xff0c;全心全意&#xff0c;永不停…...

计算机视觉(六)图像分类

文章目录 常见的CNNAlexnet1乘1的卷积 VGG网络Googlenet&#xff08;Inception V1、V2、V3&#xff09;全局平均池化总结 Resnet、ResnextResNet残差网络ResNeXt网络 应用案例VGGResnet 常见的CNN Alexnet DNN深度学习革命的开始 沿着窗口进行归一化。 1乘1的卷积 VGG网络…...

解决:vue通过params传参刷新页面参数丢失问题以及实现vue路由可选参数的解决办法

目录 &#x1f64b;‍♂️ 实现params传参&#xff0c;刷新页面不丢参 &#x1f64b;‍♂️ 实现vue配置可选路由参数 &#x1f64b;‍♂️ 参考资料 解决vue 通过 name 和 params 进行页面传参时&#xff0c;刷新页面参数丢失问题以及vue路由实现可选参数 &#x1f64b;‍♂…...

将postman接口导出的json转换为markdown

您可以使用 Postman 官方提供的工具或第三方工具将 Collection 文件转换为 Markdown 文件。 方式一 Postman 官方提供的工具是 Newman&#xff0c;它是一个命令行工具&#xff0c;可以帮助您运行和测试 Postman Collection&#xff0c;还可以将 Collection 转换为多种格式&am…...

教您一招解决找素材困难好的方法

创作视频内容时&#xff0c;找到合适的素材是至关重要的。然而&#xff0c;有时候寻找视频素材可能会变得困难。本文将分享一些实用的方法&#xff0c;帮助您轻松解决找视频素材困难的问题。 素材库和在线平台是寻找视频素材的首选方法。 利用专业的视频剪辑工具 在电脑上安…...

python_PyQt5开发验证K线视觉想法工具V1.2_批量验证

目录 运行情况&#xff1a; ​编辑 结果json文件格式&#xff1a; 代码&#xff1a; 承接 【python_PyQt5开发验证K线视觉想法工具V1.1 _增加标记类型_线段】 博文 地址&#xff1a;python_PyQt5开发验证K线视觉想法工具V1.1 _增加标记类型_线段_程序猿与金融与科技的博客-…...

应急响应-web后门(中间件)的排查思路

0x01 获取当前网络架构 语言&#xff0c;数据库&#xff0c;中间件&#xff0c;系统环境等 0x02 分析思路 1.利用时间节点筛选日志行为 2.利用已知的漏洞在日志进行特征搜索&#xff0c;快速定位到目标ip等信息 3.后门查杀&#xff0c;获取后门信息&#xff0c;进一步定位目…...

XML 学习笔记 7:XSD

本文章内容参考自&#xff1a; W3school XSD 教程 Extensible Markup Language (XML) 1.0 (Second Edition) XML Schema 2001 XML Schema Part 2: Datatypes Second Edition 文章目录 1、XSD 是什么2、XSD 内置数据类型 - built-in datatypes2.1、基本数据类型 19 种2.1.1、基本…...

neo4j图数据库基础操作命令(CQL语法)

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…...

vscode无法连接远程服务器的可能原因:远程服务器磁盘爆了

vscode输入密码后一直等待&#xff0c;无法进入远程服务器终端&#xff1a; 同时Remote-SSH输出包含以下内容 在日志中的以下几个部分&#xff1a; [17:15:05.529] > wget download failed 这表明VS Code尝试在远程服务器上下载VS Code服务器时失败了。> Cannot write…...

SSL 证书过期巡检脚本 (Python 版)

哈喽大家好&#xff0c;我是咸鱼 之前写了个 shell 版本的 SSL 证书过期巡检脚本 &#xff08;文章&#xff1a;《SSL 证书过期巡检脚本》&#xff09;&#xff0c;后台反响还是很不错的 那么今天咸鱼给大家介绍一下 python 版本的 SSL 证书过期巡检脚本 &#xff08;完整代码…...

从0到1自学网络安全(黑客)【附学习路线图+配套搭建资源】

前言 网络安全产业就像一个江湖&#xff0c;各色人等聚集。相对于欧美国家基础扎实&#xff08;懂加密、会防护、能挖洞、擅工程&#xff09;的众多名门正派&#xff0c;我国的人才更多的属于旁门左道&#xff08;很多白帽子可能会不服气&#xff09;&#xff0c;因此在未来的…...

Michael.W基于Foundry精读Openzeppelin第20期——EnumerableMap.sol

0. 版本 [openzeppelin]&#xff1a;v4.8.3&#xff0c;[forge-std]&#xff1a;v1.5.6 0.1 EnumerableMap.sol Github: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.8.3/contracts/utils/structs/EnumerableMap.sol EnumerableMap库提供了Bytes32ToB…...

深入探索二叉树:应用、计算和遍历

当涉及到二叉树的计算问题时&#xff0c;我们可以进一步介绍如何计算叶子节点数、树的宽度和叶子的深度&#xff0c;并解释三种常见的二叉树遍历方式&#xff1a;先序遍历、中序遍历和后序遍历。 1. 计算叶子节点数 叶子节点是指没有子节点的节点&#xff0c;也就是树中的末端…...

关于 1 + 1 = 2 的证明

1 1 2 首先是皮亚诺的自然数公理 意大利数学家皮亚诺提出的关于自然数的 5 5 5 条公理如下&#xff08;定义 S ( x ) S(x) S(x) 为自然数 x x x 的后继&#xff09;&#xff1a; 0 0 0 是自然数每一个自然数 n n n 都有一个自然数后继记为 S ( n ) S(n) S(n) 0 0 0 不是…...

【C++】——内存管理

目录 回忆C语言内存管理C内存管理方式new deleteoperator new与operator delete函数new和delete的实现原理定位new表达式(placement-new)malloc/free和new/delete的区别 回忆C语言内存管理 void Test() {int* p1 (int*)malloc(sizeof(int));free(p1);int* p2 (int*)calloc(4…...

Jmeter录制HTTPS脚本

Jmeter录制HTTPS脚本 文章目录 添加“HTTP代理服务器”设置浏览器代理证书导入存在问题 添加“HTTP代理服务器” 设置浏览器代理 保持端口一致 证书导入 点击一下启动让jmeter自动生成证书&#xff0c;放在bin目录下&#xff1a; 打开jmeter的SSL管理器选择刚刚生成的证书&…...

Linux 的Centos 7 安装 启动 Google Chrome

我之所以在Centos上安装Chrome主要是为了让Web自动化测试工具可以启动Chrome&#xff0c;协助我做一些工作。 参考&#xff1a;centos7 google-chrome的安装与启动 - 简书 1.安装chrome逻辑 1. 下载安装包 2. 安装 3. 启动 》这就是在window上的逻辑&#xff0c;只是用命令行…...

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

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

基于Uniapp开发HarmonyOS 5.0旅游应用技术实践

一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架&#xff0c;支持"一次开发&#xff0c;多端部署"&#xff0c;可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务&#xff0c;为旅游应用带来&#xf…...

04-初识css

一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...

LLM基础1_语言模型如何处理文本

基于GitHub项目&#xff1a;https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken&#xff1a;OpenAI开发的专业"分词器" torch&#xff1a;Facebook开发的强力计算引擎&#xff0c;相当于超级计算器 理解词嵌入&#xff1a;给词语画"…...

关于 WASM:1. WASM 基础原理

一、WASM 简介 1.1 WebAssembly 是什么&#xff1f; WebAssembly&#xff08;WASM&#xff09; 是一种能在现代浏览器中高效运行的二进制指令格式&#xff0c;它不是传统的编程语言&#xff0c;而是一种 低级字节码格式&#xff0c;可由高级语言&#xff08;如 C、C、Rust&am…...

2023赣州旅游投资集团

单选题 1.“不登高山&#xff0c;不知天之高也&#xff1b;不临深溪&#xff0c;不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

GitFlow 工作模式(详解)

今天再学项目的过程中遇到使用gitflow模式管理代码&#xff0c;因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存&#xff0c;无论是github还是gittee&#xff0c;都是一种基于git去保存代码的形式&#xff0c;这样保存代码…...

Bean 作用域有哪些?如何答出技术深度?

导语&#xff1a; Spring 面试绕不开 Bean 的作用域问题&#xff0c;这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开&#xff0c;结合典型面试题及实战场景&#xff0c;帮你厘清重点&#xff0c;打破模板式回答&#xff0c…...

安卓基础(Java 和 Gradle 版本)

1. 设置项目的 JDK 版本 方法1&#xff1a;通过 Project Structure File → Project Structure... (或按 CtrlAltShiftS) 左侧选择 SDK Location 在 Gradle Settings 部分&#xff0c;设置 Gradle JDK 方法2&#xff1a;通过 Settings File → Settings... (或 CtrlAltS)…...

Modbus RTU与Modbus TCP详解指南

目录 1. Modbus协议基础 1.1 什么是Modbus? 1.2 Modbus协议历史 1.3 Modbus协议族 1.4 Modbus通信模型 🎭 主从架构 🔄 请求响应模式 2. Modbus RTU详解 2.1 RTU是什么? 2.2 RTU物理层 🔌 连接方式 ⚡ 通信参数 2.3 RTU数据帧格式 📦 帧结构详解 🔍…...