在执行任务之前等待队列中的所有操作完成

Wan*_*use 8 nsoperation nsoperationqueue ios swift

我有一个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
}
Run Code Online (Sandbox Code Playgroud)

Rob*_*Rob 25

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

let operationQueue = OperationQueue()

let completionOperation = BlockOperation {
    // do something
}

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

OperationQueue.main.addOperation(completionOperation)
Run Code Online (Sandbox Code Playgroud)


vad*_*ian 7

一个合适的解决方案是 KVO

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

queue.addObserver(self, forKeyPath:"operations", options:.new, context:nil)
Run Code Online (Sandbox Code Playgroud)

然后执行

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:

在 Swift 4 中更容易

声明一个属性:

var observation : NSKeyValueObservation?
Run Code Online (Sandbox Code Playgroud)

并创建观察者

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
    }
}
Run Code Online (Sandbox Code Playgroud)

由于 iOS13 和 macOS15operationCount已弃用。更换就是观察progress.completedUnitCount

另一种现代方法是使用 KVO 发布者 Combine

var cancellable: AnyCancellable?

cancellable = queue.publisher(for: \.progress.completedUnitCount)
    .filter{$0 == queue.progress.totalUnitCount}
    .sink() { _ in 
       print("queue finished") 
       self.cancellable = nil           
    }
Run Code Online (Sandbox Code Playgroud)