How do I write code to be run when a group of operations finish running in an operation queue?

How do I write code that runs a block of code when a series of operations finishes? Basically I want to do with OperationQueue what I would normally do with DispatchGroup and DispatchQueue.

Accepted Reply

I would never use `waitUntilFinished: true` in the main thread.


In your example, you are just using the OperationQueue as a background sequential queue.

In such case, you can add the last Operation that runs a block of code when a series of operations finishes at the end of other Operations.


        let coordinationQueue: OperationQueue = {
            let coordinationQueue = OperationQueue()
            coordinationQueue.name = "us.gnolaum.coordinationQueue"
            coordinationQueue.maxConcurrentOperationCount = 1
            return coordinationQueue
        }()
        
        let operation1 = BlockOperation {
            //...
        }
        
        let operation2 = BlockOperation {
            //...
        }
        
        let operation3 = BlockOperation {
            //...
        }
        
        let operationreloadData = BlockOperation {
            OperationQueue.main.addOperation {
                self.tableView.reloadData()
            }
        }
        coordinationQueue.addOperations([operation1, operation2, operation3, operationreloadData], waitUntilFinished: false)
        //Do nothing more inside this method...

Replies

OperationQueue has some observable properties such as `operationCount`.


Or you can use `waitUntilAllOperationsAreFinished()` when already in background thread.


Using `dependencies` of `Operation` can be another choice.


Which best fits for your purpose may depened on your current code. Please show your code.


I would use `DispatchGroup` though.

I have made the operations to run serially in the queue by setting the max concurrent count to 1 and adding each operation to the queue to wait until finished. They are file operations, so I think they have to be done in order. I run a serios of BlockOperation objects as defined for the variable "operation". I think all I need to do is add the operation that I need to run at the end, which is defined for the variable "operationReloadData".


Am I doing this the best way possible? You said you would use DispatchGroup. I thought Apple recommends using the highest level of abstraction.



internal let coordinationQueue: OperationQueue = {
    
    let coordinationQueue = OperationQueue()
    
    coordinationQueue.name = "us.gnolaum.coordinationQueue"
    
    coordinationQueue.maxConcurrentOperationCount = 1
    
    return coordinationQueue
    
}()


        let operation = BlockOperation {
            
            let readIntent = NSFileAccessIntent.readingIntent(with: item.url, options: [])
            
            let destinationURL = self.localDocumentsURL.appendingPathComponent(item.url.lastPathComponent)
            
            let writeIntent = NSFileAccessIntent.writingIntent(with: destinationURL, options: .forReplacing)
            
            NSFileCoordinator().coordinate(with: [readIntent, writeIntent], queue: coordinationQueue) { error in
                if error != nil {
                    return
                }
                
                do {
                    
                    try self.defaultFileManager.copyItem(at: readIntent.url, to: writeIntent.url)
                    
                } catch {
                    
                    print(error.localizedDescription)
                    
                }
                
            }

        }
        
        coordinationQueue.addOperations([operation], waitUntilFinished: true)


        let operationreloadData = BlockOperation {
            
            OperationQueue.main.addOperation {
                
                self.tableView.reloadData()
                
            }
            
        }
        
        coordinationQueue.addOperations([operationreloadData], waitUntilFinished: true)

I would never use `waitUntilFinished: true` in the main thread.


In your example, you are just using the OperationQueue as a background sequential queue.

In such case, you can add the last Operation that runs a block of code when a series of operations finishes at the end of other Operations.


        let coordinationQueue: OperationQueue = {
            let coordinationQueue = OperationQueue()
            coordinationQueue.name = "us.gnolaum.coordinationQueue"
            coordinationQueue.maxConcurrentOperationCount = 1
            return coordinationQueue
        }()
        
        let operation1 = BlockOperation {
            //...
        }
        
        let operation2 = BlockOperation {
            //...
        }
        
        let operation3 = BlockOperation {
            //...
        }
        
        let operationreloadData = BlockOperation {
            OperationQueue.main.addOperation {
                self.tableView.reloadData()
            }
        }
        coordinationQueue.addOperations([operation1, operation2, operation3, operationreloadData], waitUntilFinished: false)
        //Do nothing more inside this method...

Ok. Thanks.


Are you saying that in your code the operations will run in order as you put them in the array of operations?

Are you saying that in your code the operations will run in order as you put them in the array of operations?


Surely, yes.

Ok. Thank you.