Search code examples
iosobjective-cswiftfor-loopdispatch-async

For loop with background loop, with completion?


I want to run a for loop with background code, that has something happen once it's finished iterating through every item. To do this without background code would be simple, like this:

for aString: String in strings {
    if string.utf8Length < 4 {
        continue
    }

    //Some background stuff
}

//Something to do upon completion

But to include background code in there means that the code to perform upon completion gets performed before all items are dealt with.

for aString: String in strings {
    if string.utf8Length < 4 {
        continue
    }

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {
        //Some background stuff
    }
}

//Something to do upon completion

I'm wondering if it's possible to do that.


Solution

  • Consider using a dispatch group. This provides a mechanism that notifies you when the dispatched tasks finish. So rather than dispatch_async, use dispatch_group_async:

    let group = dispatch_group_create();
    
    for aString: String in strings {
        if aString.utf8Length >= 4 {
            dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {
                //Some background stuff
            }
        }
    }
    
    dispatch_group_notify(group, dispatch_get_main_queue()) {
        // whatever you want when everything is done
    }
    

    FYI, here is an operation queue rendition of the same idea (though something that constrains the number of concurrent operations).

    let queue = NSOperationQueue()
    queue.name = "String processing queue"
    queue.maxConcurrentOperationCount = 12
    
    let completionOperation = NSBlockOperation() {
        // what I'll do when everything is done
    }
    
    for aString: String in strings {
        if aString.utf8Length >= 4 {
            let operation = NSBlockOperation() {
                // some background stuff
            }
            completionOperation.addDependency(operation)
            queue.addOperation(operation)
        }
    }
    
    queue.addOperation(completionOperation)