在iOS中具有进度报告的可取消异步操作集
假设我使用另一个SDK(我无法控制)和一个API,该API异步导入1个文件,并在完成时调用完成回调。 下面是一个示例API在iOS中具有进度报告的可取消异步操作集,ios,asynchronous,progress,operation,cancellation,Ios,Asynchronous,Progress,Operation,Cancellation,假设我使用另一个SDK(我无法控制)和一个API,该API异步导入1个文件,并在完成时调用完成回调。 下面是一个示例API func importFile(filePath: String, completion: () -> Void) 我需要使用此API导入10个文件(一个接一个),但我需要它是可取消的,例如,在成功导入文件1、2、3后,在导入文件4时,我希望能够取消整个操作集(导入10个文件),这样文件4将完成(因为它已经启动),但文件5-10将不再导入 此外,我还需要报告导入的进
func importFile(filePath: String, completion: () -> Void)
我需要使用此API导入10个文件(一个接一个),但我需要它是可取消的,例如,在成功导入文件1、2、3后,在导入文件4时,我希望能够取消整个操作集(导入10个文件),这样文件4将完成(因为它已经启动),但文件5-10将不再导入
此外,我还需要报告导入的进度。成功导入文件1后,我应该报告10%的进度(10个中有1个已经完成)
我怎样才能做到这一点
我正在考虑将NSOperationQueue与10个NSOperations一起使用,但似乎进度报告会很困难。
NSOperationQueue
提供了一个很好的面向对象的抽象功能,这是我将采用的方法
- 创建名为
importQueue
- 创建一个
NSOperation
- 存储要访问的操作,并可能在以后将其取消,例如在字典中[ImportNumber:NSOperation]
- 将操作添加到
importQueue
关于进展情况: 备选案文1:
NSOperationQueue
有一个名为operations
的属性,您可以观察该属性的计数。(importQueue.operations.count
)
备选案文2:
NSOperation
提供完成块。您可以在操作排队时增加计数器,在完成块内或取消时减少计数器
进一步阅读:,。我认为您应该在您的操作上添加依赖项。 这个想法是:
1Op = NSOperation..
2Op = NSOperation..
.
.
10Op = NSOperation..
10Op.addDependency(9Op)
9Op.addDependency(8Op) and so on...
然后,您的操作子类应该以这种方式重写cancel方法
cancel() {
super.cancel()
for dep in dependencies {
dep.cancel()
}
}
所以,我相信这就是你想从你的问题中得到的:
NSOperationQueue
和NSBlockOperation
实现
AsyncBlockOperation
和NSOperationQueue+AsyncBlockOperation
类:NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
operationQueue.maxConcurrentOperationCount = 1;
operationQueue.name = @"com.yourOrganization.yourProject.yourQueue";
- (void)importFilesFromFilePathArray:(NSArray *)pathsArray
inOperationQueue:(NSOperationQueue *)operationQueue
withProgress:(void (^)(CGFloat progress))progressBlock {
}
2
中定义的函数内,使用NSBlockOperation
执行NSOperationQueue中的操作
for (int i = 0; i < pathsArray.count; i++) {
[operationQueue addAsyncOperationWithBlock:^(dispatch_block_t completionHandler) {
[self importFile:(NSString *)[pathsArray objectAtIndex:i] completion:^(bool completion) {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
CGFloat progress = (100 * (float)(i+1)/pathsArray.count);
progressBlock(progress);
if (progress == 100) {
successBlock(YES);
}
}];
completionHandler();
}];
}];
}
我自己也试过这个代码。它工作得很好。请随时提出改进建议:)请检查我的答案,并让我知道这是否是您想要的。事实上,我认为我们也可以使用
dispatch\u suspend
来解决此问题。您是否正在寻找仅基于NSOperation的解决方案?我对我的答案进行了编辑,使其能够回答您的所有查询。我谦恭地请你看一看。看起来不错。但是,如果importFile是异步的,如问题描述中所述,您会怎么做?那么,当所有操作都已完成时,完成回调如何处理该要求呢?我会在几分钟后补充说,如果进度为100,那么这意味着它是成功的。在这里,当您可以选择手动取消操作时,故障报告变得很困难。小疑问:如果其中一个文件导入失败,我们应该继续还是取消所有操作?此外,由于您的importFile
函数是异步的,您可以使用NSOperationBlock代替正常的NSOperationBlock,因此您建议为NSOperation的子类使用异步类型的实现。谢谢您将如何为异步API实现NSOperation(如问题描述中所述)?具体的实现将太长,而且imo。因此不打算提供这一点。如果您在阅读本教程后有任何问题,请告知我们,可能是针对您遇到的特定新问题的新问题。简单的回答是可以的。问题明确指出API(来自第三方SDK)是异步的,您的答案使用同步API。NSO操作可以运行同步(或非并发)和异步(或并发)。所有这些都在所提到的教程中得到了很好的解释。您提到的教程中的NSO操作(ImageDownloader和ImageFiltering)仅使用同步API。您指的是什么异步API?进度报告和完成回调如何?在您的操作中,您可以调用进度更新委托
[operationQueue cancelAllOperations];