StCleezy
StCleezy

Reputation: 135

Swift UI update in callback is sometimes not executed

When executing the code below, I see the callback execute (verified by "success!"), but the activityIndicator on the UI activityIndicator doesn't stop spinning.

Sometimes it will stop after 10-20 seconds, and other times it will run forever. The callback should be running on the main thread, so I'm not sure what's causing it to delay / fail.

activityIndicator.startAnimating()
loadData("data") {(success: Bool) in
    if success {
        // I see this being printed
        println("success!")
    }

    // This isn't updating on the UI! The wheel keeps spinning
    self.activityIndicator.stopAnimating()
}

The loadData function is performing a block save using Core Data:

public func loadData(completionHandler: (success: Bool) -> Void) {
    let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
    let appContext = appDelegate.managedObjectContext!
    let managedContext = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
    managedContext.persistentStoreCoordinator = appContext.persistentStoreCoordinator

    managedContext.performBlock({

        //NSManagedObject inserts - working...

        if !managedContext.save(&error) {
            completionHandler(success: false)
        }
    completionHandler(success: true)
    })
}

Any help here is much appreciated!

Upvotes: 3

Views: 2929

Answers (2)

Fred Faust
Fred Faust

Reputation: 6800

I had a similar issue and solved it by first animating the activity indicator, then dropping the rest of the code to a background thread, then calling stop animating on the main thread.

activityIndicator.startAnimating()
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), { ()->() in
loadData("data") {(success: Bool) in
if success {
    // I see this being printed
    println("success!")
}

// This isn't updating on the UI! The wheel keeps spinning
 dispatch_async(dispatch_get_main_queue(), {
self.activityIndicator.stopAnimating()
})
}

I didn't update the closing brackets here assuming you have more because of the closure you're working in.

Upvotes: 0

Christos Chadjikyriacou
Christos Chadjikyriacou

Reputation: 3759

    activityIndicator.startAnimating()
loadData("data") {(success: Bool) in
    if success {
        // I see this being printed
        println("success!")
    }

    dispatch_async(dispatch_get_main_queue()) {
    // This isn't updating on the UI! The wheel keeps spinning
    self.activityIndicator.stopAnimating()
    }
}

Also i noticed that you are calling the completion block two times if there is an error.So add a return after the first completion block. Like this:

public func loadData(completionHandler: (success: Bool) -> Void) {
let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
let appContext = appDelegate.managedObjectContext!
let managedContext = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
managedContext.persistentStoreCoordinator = appContext.persistentStoreCoordinator

managedContext.performBlock({

    //NSManagedObject inserts - working...

    if !managedContext.save(&error) {
        completionHandler(success: false)
        return
    }
completionHandler(success: true)
})

}

Upvotes: 4

Related Questions