在执行任务

时间:2017-02-27 21:07:43

标签: ios swift nsoperation nsoperationqueue

我有一个Operation子类和操作队列,maxConcurrentOperationCount = 1。

这按顺序执行我的操作,我添加它们很好,但现在我需要等到所有操作完成后再运行另一个进程。

我正在尝试使用通知组,但是一旦将操作添加到队列中,这就会在for循环中运行,通知组将触发..如何在运行另一个操作之前等待所有操作离开队列过程

for (index, _) in  self.packArray.enumerated() {

    myGroup.enter()
    let myArrayOperation = ArrayOperation(collection: self.outerCollectionView, id: self.packArray[index].id, count: index)
    myArrayOperation.name = self.packArray[index].id
    downloadQueue.addOperation(myArrayOperation)
    myGroup.leave()

}

myGroup.notify(queue: .main) {
 // do stuff here
}

6 个答案:

答案 0 :(得分:16)

您可以使用操作依赖关系在完成一系列其他操作后启动某些操作:

let operationQueue = OperationQueue()

let completionOperation = BlockOperation {
    // do something
}

for object in objects {
    let operation = ...
    completionOperation.addDependency(operation)
    operationQueue.addOperation(operation)
}

OperationQueue.main.addOperation(completionOperation)

答案 1 :(得分:3)

合适的解决方案是KVO

首先在循环之前添加观察者(假设queueOperationQueue实例)

queue.addObserver(self, forKeyPath:"operations", options:.new, context:nil)

然后实施

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if object as? OperationQueue == queue && keyPath == "operations" {
        if queue.operations.isEmpty {
            // Do something here when your queue has completed
            self.queue.removeObserver(self, forKeyPath:"operations")
        }
    } else {
        super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
    }
}

修改

在Swift 4中,它更容易

声明属性:

var observation : NSKeyValueObservation?

并创建观察者

observation = queue.observe(\.operationCount, options: [.new]) { [unowned self] (queue, change) in
    if change.newValue! == 0 {
        // Do something here when your queue has completed
        self.observation = nil
    }
}

答案 2 :(得分:1)

我使用下一个解决方案:

private let queue = OperationQueue()

private func addOperations(_ operations: [Operation], completionHandler: @escaping () -> ()) {
    DispatchQueue.global().async { [unowned self] in
        self.queue.addOperations(operations, waitUntilFinished: true)
        DispatchQueue.main.async(execute: completionHandler)
    }
}

答案 3 :(得分:0)

将最大并发操作数设置为1

operationQueue.maxConcurrentOperationCount = 1

然后将按顺序执行每个操作(就像每个操作都依赖于上一个操作一样),并且您的完成操作将在最后执行。

答案 4 :(得分:0)

队列末尾的代码 请参阅this link

NSOperation和NSOperationQueue是用于异步任务的出色且有用的Foundation框架工具。但是,有一件事使我感到困惑:在所有队列操作完成后,如何运行代码?简单的答案是:使用队列中的操作之间的依赖关系(NSOperation的独特功能)。这只是5行代码解决方案。

NSOperation依赖技巧 使用Swift可以很容易地实现:

extension Array where Element: NSOperation {
/// Execute block after all operations from the array.
func onFinish(block: () -> Void) {
    let doneOperation = NSBlockOperation(block: block)
    self.forEach { [unowned doneOperation] in doneOperation.addDependency($0) }
    NSOperationQueue().addOperation(doneOperation)
}}

答案 5 :(得分:0)

我的解决方案与https://stackoverflow.com/a/42496559/452115相似,但是我没有在主OperationQueue中添加completionOperation,而是将其添加到队列本身中。这对我有用:

var a = [Int](repeating: 0, count: 10)

let queue = OperationQueue()

let completionOperation = BlockOperation {
    print(a)
}

queue.maxConcurrentOperationCount = 2
for i in 0...9 {
    let operation = BlockOperation {
        a[i] = 1
    }
    completionOperation.addDependency(operation)
    queue.addOperation(operation)
}

queue.addOperation(completionOperation)

print("Done ?")