【问题标题】:AFNetworking & handling NSOperationQueue - execute code on completion and track progressAFNetworking 和处理 NSOperationQueue - 在完成时执行代码并跟踪进度
【发布时间】:2013-05-17 15:27:15
【问题描述】:

我正在使用AFNetworking 库,这非常好,但是我在跟踪 NSOperationQueue 中的操作时遇到了麻烦。我正在将 NSOperation 对象添加到 NSOperationQueue,并且我需要跟踪进度 - 因此更新 UIProgressView 以显示队列完成的距离,然后在队列完成后执行一段代码。

我已经尝试过 KVO - 在这里使用答案:Get notification when NSOperationQueue finishes all tasks 但是我遇到了一个问题(详细说明了那里的第二个答案),有时队列中的操作可能完成得足够快,可以暂时将 operationCount 属性递减为 0 - 这会导致已接受答案中的代码出现问题 - 即在队列中的所有对象完成后过早执行要执行的代码,因此进度跟踪将不准确。

我尝试过的一个变体是在我添加到 NSOperationQueue 的每个 NSOperation 的成功块中检查 operationCount == 0,然后基于它执行代码,例如

    [AFImageRequestOperation *imgRequest = [AFImageRequestOperation imageRequestOperationWithRequest:urlRequest success:^(UIImage *image) {

     //Process image & save

            if(operationQ.operationCount == 0){
              // execute completion of Queue code here
            }
            else {
              // track progress of the queue here and update UIProgressView
            }
    }];

但是,我遇到了与 KVO 相同的问题。

我考虑过使用 GCD 和使用完成块的调度队列 - 所以异步调度 NSOperationQueue 然后执行完成块,但这并不能解决我关于跟踪队列进度以更新 UIProgressView 的问题.

也没用过

AFHttpClient enqueueBatchOfHTTPRequestOperations:(NSArray *) progressBlock:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations)progressBlock completionBlock:^(NSArray *operations)completionBlock

因为我的图片来自几个不同的网址(而不是一个基本网址)。

任何建议或指示将不胜感激。谢谢。

只是最后一次更新:

最终在 Matt 的帮助下使用 AFHTTPClient enqueueBatchOfHTTPRequestOperations 解决了这个问题(请参阅已接受的答案),并注意 cmets。

我确实遇到了另一个不使用 AFHTTPClient 而是单独使用 NSOperationQueue 的解决方案。我也将其包括在内,以防它对任何人都有用,但如果您使用的是 AFNetworking 库,我会推荐接受的答案(因为它最优雅且易于实施)。

【问题讨论】:

  • 您看到链接问题的第二个答案了吗?这是解决问题的一种可能方法。
  • 我确实看过那个 Cory,我尝试使用依赖项,但它仍然没有给我一个解决方案,除非我对该方法的应用不正确..

标签: ios objective-c afnetworking


【解决方案1】:

如果您只使用 NSOperationQueue 而不是 AFHTTPClient,另一个(不那么优雅)的解决方案如下(假设以下代码将在某个循环中创建多个请求并添加到 NSOperationQueue)。

       [AFImageRequestOperation *imgRequest = [AFImageRequestOperation imageRequestOperationWithRequest:urlRequest success:^(UIImage *image) {

     //Process image & save

      operationNum++ 
      //initially operationNum set to zero, so this will now increment to 1 on first run of the loop

      if(operationNum == totalNumOperations){ 
         //totalNumOperations would be set to the total number of operations you intend to add to the queue (pre-determined e.g. by [array count] property which would also be how many times the loop will run)

         // code to execute when queue is finished here
       }
       else {
          // track progress of the queue here and update UIProgressView

          float progress = (float)operationNum / totalNumOperations
          [progView setProgress:progress] //set the UIProgressView.progress property
        }
     }];

将这些 NSOperation 对象添加到 NSOperationQueue 将确保每个操作的成功块在执行嵌入在每个 NSOperation 对象的成功块中的队列完成代码之前完成。注意 NSOperationQueue.operationCount 属性没有被使用,因为它在快速操作上不可靠,因为在一个操作退出队列和添加下一个操作之前可能存在一个状态,其中 operationCount 为零,所以如果我们比较 NSOperationQueue。 operationCount = 0 而不是队列的完成代码会提前执行。

【讨论】:

    【解决方案2】:

    AFHTTPClient -enqueueBatchOfHTTPRequestOperations:progressBlock:completionBlock: 是执行此操作的正确方法。该方法采用一组请求操作,可以从任意请求构建,而不仅仅是共享域的请求。

    【讨论】:

    • 请求是否共享AFHTTPClient的base url是否无关紧要?在初始化 AFHTTPClient 时,什么是合适的基本 url,或者可以在不分配它的情况下调用 init 方法,即 [[AFHTTPClient alloc] init]?
    • 我只是尝试了它并附加了一个任意的基本 URL(例如google.com) - 它似乎表现出与我上面的代码相同的行为。我认为正在发生的事情是,一旦项目全部从队列中释放,但甚至在每个队列项目的成功块完成执行之前,完成块就会执行 - 有没有办法在 AFHTTPClient 中延迟完成块的执行,直到所有代码在包括附加到每个成功块的操作是否完成?
    • 无法保证完成块的执行时间。我的建议是不要在批处理操作中使用completionBlocks,并在批处理完成块中完成所有必要的工作。
    • 谢谢你,马特,它似乎是最优雅的解决方案,只是为了补充你的评论 - 最终真正解决我的问题的是使用操作的输出流(详见此处: stackoverflow.com/questions/8372661/…) 来保存文件 - 以前我是通过操作完成块手动执行此操作(将图像转换为数据,然后 writeToFile),因此不能保证它是及时写入批处理完成块。
    • 还有一件事要添加 - 我看到批处理完成块提供对批处理中的操作数组以及响应数据(例如响应 UIImage)的访问,这将允许一个人做所有的处理都在这个批处理完成块中而不是在每个操作的成功块中,确保一切都是及时的,正如你所建议的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-18
    • 2023-03-31
    • 2014-07-07
    • 2012-06-18
    相关资源
    最近更新 更多