MaxConcurrentOperationCount = 1のOperationサブクラスとOperationキューがあります。
これにより、操作が順番に実行され、追加されます。これは問題ありませんが、すべての操作が完了するまで待ってから、別のプロセスを実行する必要があります。
通知グループを使用しようとしましたが、操作がキューに追加されるとすぐに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
}
操作の依存関係を使用して、他の一連の操作の完了時にいくつかの操作を開始できます。
let operationQueue = OperationQueue()
let completionOperation = BlockOperation {
// do something
}
for object in objects {
let operation = ...
completionOperation.addDependency(operation)
operationQueue.addOperation(operation)
}
OperationQueue.main.addOperation(completionOperation)
適切なソリューションはKVOです
最初にループの前にオブザーバーを追加します(queue
がOperationQueue
インスタンスであると仮定します)
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
}
}
私は次の解決策を使用します:
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
次に、各操作が順番に実行され(それぞれが前の操作に依存しているかのように)、完了操作が最後に実行されます。
私の解決策は 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 ????")
キューの最後のコードは このリンク を参照します
NSOperationとNSOperationQueueは、非同期タスク用の優れた便利なFoundationフレームワークツールです。しかし、私を困惑させたのは、すべてのキュー操作が終了した後にコードを実行するにはどうすればよいですか?簡単な答えは、キュー内の操作間の依存関係を使用することです(NSOperationの独自の機能)。たった5行のコードソリューションです。
NSOperation依存関係トリックwith 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)
}}