You asked: "How can I return the desired, updated array at the end of the request method?" Short answer: you cannot.
This is the fundamental value of asynchronous coding.
The readWithCompletion method is asynchronous. It pauses your request for processing in the background, and returns immediately.
Your return events //still empty code is executed before your read request has even started processing.
You need to reorganize your getAllEventIDs method to take the completion block as a parameter. This completion block will be passed by your event array. Then inside the completion block for readWithCompletion you call the completion block for your getAllEventIDs method.
So when you call getAllEventIDs , you pass it a completion block that does what you need to do with the array of events.
EDIT:
I created a Github project called SwiftCompletionHandlers that illustrates this and how to handle it. It has an example AsyncManager class that simulates asynchronous loading.
https://github.com/DuncanMC/SwiftCompletionHandlers
He has a method that looks like this:
func asyncFetchImage(#imageName: String, completion: ( image: UIImage?, status: String) -> ()) { println("Entering \(__FUNCTION__)") //Simulate a network operation by waiting a few seconds //before loading an image let nSecDispatchTime = dispatch_time(DISPATCH_TIME_NOW, Int64(3.0 * Double(NSEC_PER_SEC))) let queue = dispatch_get_main_queue() dispatch_after(nSecDispatchTime, queue) { () -> Void in let result = UIImage(named: imageName) println("Loading image in background") let status = result != nil ? "image loaded" : "Error loading image" println("About to call completion handler") completion(image: result, status: status) } println("Leaving \(__FUNCTION__)") }
A file name and a termination block are required. The completion block receives the passed optional UIImage and a string status message.
Once the download is complete, the method calls the completion block (aka clos.)
Here is the code that calls this method:
@IBAction func loadImage(sender: UIButton) { let theAsyncManager = AsyncManager.sharedAsyncManager println("about to call asyncFetchImage") theAsyncManager.asyncFetchImage(imageName: "wareto_blue_150x115") { (image, status) -> () in println("Beginning completion block") self.theImageView.image = image println("In completion block, status = \(status)") } println("After call to asyncFetchImage") }
The output of println statements is key to understanding what is happening:
about to call asyncFetchImage Entering asyncFetchImage(imageName:completion:) Leaving asyncFetchImage(imageName:completion:) After call to asyncFetchImage Loading image in background About to call completion handler Beginning completion block In completion block, status = image loaded
Please note that the messages "Exit asyncFetchImage" and "After calling asyncFetchImage" are printed before the message "Download image in the background." Then “About the call to the completion handler” appears, then “Start of the completion block”.
Thus, the actual operation of async does not even start until the loadImage function returns.
If you do not understand what I am describing, download the project and try it, then set breakpoints and see how they are executed.