在iOS

时间:2016-10-26 14:31:22

标签: ios asynchronous progress operation cancellation

假设我使用另一个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,但似乎进度报告很难。

3 个答案:

答案 0 :(得分:1)

所以,我相信你想从你的问题中得到以下内容:

  1. 在队列中逐个导入n个文件
  2. 报告导入每个文件的进度
  3. 能够取消中间的操作
  4. 可以通过以下方式使用NSOperationQueueNSBlockOperation来实现。

    1. 根据以下StackOverflow问题的答案中的代码创建AsyncBlockOperationNSOperationQueue+AsyncBlockOperation类:NSOperation wait until asynchronous block executes
    2. 将这两个类导入到将要使用的文件中
    3. 创建操作队列

      NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
      operationQueue.maxConcurrentOperationCount = 1;
      operationQueue.name = @"com.yourOrganization.yourProject.yourQueue";
      
    4. 创建一个函数,为您提供回调以获取进度

      - (void)importFilesFromFilePathArray:(NSArray *)pathsArray
                          inOperationQueue:(NSOperationQueue *)operationQueue
                              withProgress:(void (^)(CGFloat progress))progressBlock {
      
        }
      
    5. 2中定义的函数内,使用NSBlockOperationNSOperationQueue

      中执行操作
      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();
               }];
           }];
      }
      
    6. 对于取消操作,我们只需使用我们在第一步中创建的operationQueue

      [operationQueue cancelAllOperations];
      
    7. 我自己尝试了这段代码。它运作良好。随意提出改进建议,使其更好:)

答案 1 :(得分:0)

NSOperationQueue提供了一个很好的面向对象的抽象,是我的方式。

  • 创建名为NSOperationQueue
  • importQueue

每次导入:

  • 创建NSOperation
  • 将操作存储到以后并可能将其打包,例如在字典中[ImportNumber:NSOperation]
  • 将操作添加到importQueue

关于进展状态:

选项1:

NSOperationQueue有一个名为operations的属性,您可以观察到这些属性。 (importQueue.operations.count)。

选项2:

NSOperation提供完成功能块。您可以在排队操作时增加计数器,并在完成块内或取消时减少它。

进一步阅读:Apple documentationasynchronous-nsoperation-why-and-hownice 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()
    }
}