假设我使用另一个SDK(我无法控制)和一个异步导入1个文件的API,并在完成时调用完成回调。 以下是API示例。
func importFile(filePath: String, completion: () -> Void)
我需要使用此API导入10个文件(逐个),但我需要它可以取消,例如在成功导入文件1,2,3之后,在导入文件4时,我希望能够取消整个操作集(导入10个文件),这样文件4就会完成(因为它已经开始了) ),但不再导入文件5-10。
此外,我还需要报告导入的进度。成功导入文件1后,我应该报告10%的进度(10个中有1个已经完成)。
我怎样才能做到这一点?
我正在考虑使用NSOperationQueue和10个NSOperations,但似乎进度报告很难。
答案 0 :(得分:1)
所以,我相信你想从你的问题中得到以下内容:
可以通过以下方式使用NSOperationQueue
和NSBlockOperation
来实现。
AsyncBlockOperation
和NSOperationQueue+AsyncBlockOperation
类:NSOperation wait until asynchronous block executes 创建操作队列
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();
}];
}];
}
对于取消操作,我们只需使用我们在第一步中创建的operationQueue
[operationQueue cancelAllOperations];
我自己尝试了这段代码。它运作良好。随意提出改进建议,使其更好:)
答案 1 :(得分:0)
NSOperationQueue
提供了一个很好的面向对象的抽象,是我的方式。
NSOperationQueue
importQueue
每次导入:
NSOperation
importQueue
关于进展状态:
选项1:
NSOperationQueue
有一个名为operations
的属性,您可以观察到这些属性。 (importQueue.operations.count
)。
选项2:
NSOperation
提供完成功能块。您可以在排队操作时增加计数器,并在完成块内或取消时减少它。
进一步阅读:Apple documentation,asynchronous-nsoperation-why-and-how,nice but oldish tutorial。
答案 2 :(得分:0)
我认为您应该在操作中添加依赖项。 这个想法是这样的:
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()
}
}