Ios 等待队列中的所有操作完成,然后再执行任务

Ios 等待队列中的所有操作完成,然后再执行任务,ios,swift,nsoperation,nsoperationqueue,Ios,Swift,Nsoperation,Nsoperationqueue,我有一个操作子类和maxConcurrentOperationCount=1的操作队列 这将按照我添加操作的顺序执行操作,这很好,但现在我需要等到所有操作完成后再运行另一个进程 我试图使用通知组,但由于这是在for循环中运行的,一旦操作添加到队列中,通知组就会触发。。在运行另一个进程之前,如何等待所有操作离开队列 for (index, _) in self.packArray.enumerated() { myGroup.enter() let myArrayOperati

我有一个操作子类和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
}

一个合适的解决方案是KVO

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

然后实施

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
    }
}

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

let queue = OperationQueue()

let completionOperation = BlockOperation {
    // all done
}

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

OperationQueue.main.addOperation(completionOperation)  // or, if you don't need it on main queue, just `queue.addOperation(completionOperation)`
或者,在iOS 13及更高版本中,您可以使用屏障:

let queue = OperationQueue()

for object in objects {
    queue.addOperation(...)
}

queue.addBarrierBlock {
    DispatchQueue.main.async {
        // all done
    }
}

我使用下一个解决方案:

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)
    }
}

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

operationQueue.maxConcurrentOperationCount = 1

然后,每个操作将按顺序执行(好像每个操作都依赖于前一个操作),完成操作将在最后执行。

队列末尾的代码

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

操作依赖技巧 借助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)
}}

我的解决方案与的类似,但我没有将
completionOperation
添加到主操作队列中,而是添加到队列本身中。这对我很有用:

var a=[Int](重复:0,计数:10)
let queue=OperationQueue()
let completionOperation=BlockOperation{
印刷品(a)
}
queue.maxConcurrentOperationCount=2
因为我在0…9{
let操作=块操作{
a[i]=1
}
completionOperation.addDependency(操作)
queue.addOperation(操作)
}
queue.addOperation(completionOperation)

打印(“完成”放入
myGroup.leave()
在操作的完成块中。使用WaitUntillall操作完成得非常干净。谢谢Rob,我已经完成了这项操作,但是我的
完成操作
仍然被提前触发。我的操作是异步网络操作,因此只有当响应返回时才认为操作已完成。我读到我需要覆盖
isAsynchronous
属性和其他一些属性以使其成为异步操作,但我读到如果我将操作添加到队列中,该属性将被忽略。因此我不知道该怎么做。请您进一步建议好吗?如果循环中有一个操作数组,我想等待r所有这些
isAsynchronous
:添加到队列时,确实会忽略
isAsynchronous
,但所有
isExecuting
都已完成
,并且在添加将某个异步进程包装到队列的操作时,需要相关的KVO。尽管如此,我相信这是最佳实践在操作确实是异步的情况下,将
isAsynchronous
设置为
true
,以(a)反映操作的真实性和(b)为了确保它在队列中使用或刚刚手动启动时都能工作。关于此处的操作依赖项技术,它看起来像是
main
OperationQueue
上的一个类变量?该行是否应更改为
OperationQueue.main.addOperation(completionOperation)
?这是否具有相同的含义?
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)
}}