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

lztngnrs  于 12个月前  发布在  Swift
关注(0)|答案(7)|浏览(118)

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

字符串

e5nszbig

e5nszbig1#

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

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

jrcvhitl

jrcvhitl2#

合适的解决方案是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中,
December属性:

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


由于iOS13和macOS15不推荐使用operationCount。替换是观察progress.completedUnitCount
另一种现代方法是使用Combine的KVO发布程序

var cancellable: AnyCancellable?

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

zpjtge22

zpjtge223#

我使用下一个解决方案:

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

字符串

i7uq4tfw

i7uq4tfw4#

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

operationQueue.maxConcurrentOperationCount = 1

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

tquggr8v

tquggr8v5#

队列末尾代码参考this link

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

NSOption依赖技巧使用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)
}}

字符串

qv7cva1a

qv7cva1a6#

我的解决方案类似于https://stackoverflow.com/a/42496559/452115,但我没有将completionOperation添加到主OperationQueue中,而是添加到队列本身。这对我来说很有效:

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 🎉")

字符串

1hdlvixo

1hdlvixo7#

我也遇到过这个问题。好吧,GCD已经提供了API:dispatch_group,而不是NSOperation,例如:

dispatch_group_t myGroup = dispatch_group_create();

// task1
dispatch_group_enter(myGroup);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // excute task1
    // ...

    // task1 completed,leave group
    dispatch_group_leave(myGroup);
});

// task2
dispatch_group_enter(myGroup);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // excute task2
    // ...

    // task2 completed,leave group
    dispatch_group_leave(myGroup);
});

dispatch_group_notify(myGroup, dispatch_get_main_queue(), ^{
    // call back on all tasks c finished
    NSLog(@"all tasks are finished");
});

// continue other tasks.

字符串

相关问题