user1019042 user1019042 - 5 months ago 23
Swift Question

Swift: block all code until a function finishes executing

I am calling a function that gets crucial data from serve. I want all code to wait until that happens. I tried using semaphore but it doesn't seem to work like expected. My code is like so:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
getUserById(userIDParam)
thisShouldWait()
....

func getUserById(id: Int) -> Void {
let semaphore = dispatch_semaphore_create(0)
WebService.getUserById(id) { user in
AppDelegate.CurrentUser = user
}
}


the function: thisShouldWait() executes before the the completion handler finishes. So I tried using semaphore, but that ran indefinitely. What is the solution? my serverice getUserById:

class func getUserById(userID: Int, completionHandler: (User) -> Void) -> Void {

let semaphore = dispatch_semaphore_create(0)
let defaultSession = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())

let methodParameters = []

let url = appDelegate.URL

let dataTask: NSURLSessionDataTask = defaultSession.dataTaskWithURL(url, completionHandler: {(data, response, error) -> Void in

if error != nil {
} else if let httpResponse = response as? NSHTTPURLResponse {
if httpResponse.statusCode >= 200 || httpResponse.statusCode <= 299 {
let user: User = parseSearchResults(data)
completionHandler(user)
}
}
})

dataTask.resume()

dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
}

Answer

You are missing a dispatch_semaphore_signal in your completion handler:

let dataTask: NSURLSessionDataTask = defaultSession.dataTaskWithURL(url) { data, response, error in
    if error != nil {
    } else if let httpResponse = response as? NSHTTPURLResponse {
        if httpResponse.statusCode >= 200 || httpResponse.statusCode <= 299 {
            let user: User = parseSearchResults(data)
            completionHandler(user)
        }
    }
    dispatch_semaphore_signal(semaphore) // Added
}

Make sure you call getUserById on a background thread. Locking up the UI when it's being done is never a good idea.