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