【问题标题】:NSOperationQueue addOperations waitUntilFinishedNSOperationQueue addOperations waitUntilFinished
【发布时间】:2015-07-11 15:09:16
【问题描述】:

您好,我正在使用 Swift 构建应用程序。我需要按特定顺序处理通知。因此我尝试使用 addOperations waitUntilFinished。

这是我所做的:

let oldify = NSOperation()
    oldify.completionBlock = {
println("oldify")
}
let appendify = NSOperation()
    appendify.completionBlock = {
println("appendify")
}
let nettoyify = NSOperation()
    nettoyify.completionBlock = {
println("nettoyify")
}
NSOperationQueue.mainQueue().maxConcurrentOperationCount = 1
NSOperationQueue.mainQueue().addOperations([oldify, appendify, nettoyify], waitUntilFinished: true)

使用此代码不会执行任何操作。当我尝试这样做时:

NSOperationQueue.mainQueue().maxConcurrentOperationCount = 1
NSOperationQueue.mainQueue().addOperation(oldify)
NSOperationQueue.mainQueue().addOperation(appendify)
NSOperationQueue.mainQueue().addOperation(nettoyify)

操作被执行但顺序不正确。

有谁知道我做错了什么?我对 NSOperations 的快速但全新的体验越来越有信心

【问题讨论】:

标签: ios swift nsoperation nsoperationqueue


【解决方案1】:

几个问题:

  1. 您正在检查完成块处理程序的行为。正如completionBlock 文档所说:

    无法保证完成块的确切执行上下文,但通常是辅助线程。因此,您不应使用此块来执行任何需要非常特定的执行上下文的工作。

    队列将自己管理操作,而不是它们的完成块(没有确保操作在其completionBlock 开始之前完成)。因此,最重要的是,不要对 (a) 何时运行完成块,(b) 一个操作的 completionBlock 与其他操作或其 completionBlock 块等的关系,以及 (c) 哪个线程做任何假设他们被执行。

  2. 操作通常按照它们添加到队列中的顺序执行。但是,如果您添加一组操作,则文档不会正式保证它们按照它们在该数组中出现的顺序排列。因此,您可能希望一次添加一个操作。

  3. 话虽如此,文档继续警告我们:

    操作队列根据其优先级和准备情况执行其排队的操作对象。如果所有排队的操作对象具有相同的优先级并且在它们被放入队列时准备好执行——也就是说,它们的isReady方法返回YES——它们将按照它们被提交到队列的顺序执行。队列。但是,您永远不应依赖队列语义来确保操作对象的特定执行顺序。操作准备情况的更改可能会更改生成的执行顺序。如果您需要按特定顺序执行操作,请使用 NSOperation 类定义的操作级依赖项。

    要建立显式依赖关系,您可以执行以下操作:

    let oldify = NSBlockOperation() {
        NSLog("oldify")
    }
    oldify.completionBlock = {
        NSLog("oldify completion")
    }
    
    let appendify = NSBlockOperation() {
        NSLog("appendify")
    }
    appendify.completionBlock = {
        NSLog("appendify completion")
    }
    
    appendify.addDependency(oldify)
    
    let nettoyify = NSBlockOperation() {
        NSLog("nettoyify")
    }
    nettoyify.completionBlock = {
        NSLog("nettoyify completion")
    }
    
    nettoyify.addDependency(appendify)
    
    let queue = NSOperationQueue()
    queue.addOperations([oldify, appendify, nettoyify], waitUntilFinished: false)
    
  4. 顺便说一句,正如您将在上面看到的,您不应将操作与waitUntilFinished 一起添加到主队列。随意将它们添加到不同的队列,但不要使用waitUntilFinished 选项从串行队列分派回自身。

【讨论】:

  • 非常感谢@Rob。我现在看起来更清楚了。我仍然面临一个问题。在 appendify 块中,我正在使用 findObjectsInBackgroundWithBlock 运行解析请求。结果是 oldify、appendify 和 nettoyify 正在以正确的顺序执行,但请求(假设在 appendify 内部)在所有操作之后返回结果。我正在尝试在主线程上执行该请求,因为我已经设置了 queue.qualityOfService = NSQualityOfService.UserInitiated
  • 您的操作正在进行findObjectsInBackgroundWithBlock?如果是这样,那是一个异步请求,所以我敢打赌,您的操作很可能在 Parse 查询完成之前完成。两种解决方案:要么将它们包装在异步 NSOperation 子类中,该子类仅在请求完成时手动完成操作,要么让您的操作发出同步请求(但确保将这些操作添加到您自己的队列,而不是主队列)。
  • 非常感谢@Rob。我选择使用.find() 而不是findObjectsInBackgroundWithBlock 来执行同步请求。我不得不将waitUntilFinished 设置为true。这是一个问题,因为所有这些都不会发生在主队列上吗?
  • 为什么需要waitUntilFinished?将任何依赖于这些基于find 的操作的内容放在另一个操作中,并使其依赖于其他操作。你真的不想使用waitUntilFinished,除非绝对必要(它不在这里)。在回答你的问题时,不,你永远不会从主线程调用waitUntilFinished(不管后台线程上的操作是什么)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-05
  • 1970-01-01
  • 2011-12-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多