web-dev-qa-db-ja.com

タスクを実行する前に、キュー内のすべての操作が終了するのを待ちます

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

操作の依存関係を使用して、他の一連の操作の完了時にいくつかの操作を開始できます。

let operationQueue = OperationQueue()

let completionOperation = BlockOperation {
    // do something
}

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

OperationQueue.main.addOperation(completionOperation)
22
Rob

適切なソリューションは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では、はるかに簡単です

プロパティを宣言します。

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

私は次の解決策を使用します:

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
kasyanov-ms

同時操作の最大数を1に設定します

operationQueue.maxConcurrentOperationCount = 1

次に、各操作が順番に実行され(それぞれが前の操作に依存しているかのように)、完了操作が最後に実行されます。

0
dbolli

私の解決策は 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 ????")
0
Peacemoon

キューの最後のコードこのリンク を参照します

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