1

The following function is being used to synchronize the app with json data from a server and this takes up a few a minutes if the content hasn't been updated for a while. As for now, the app blocks the main UI and tells the user that it's updating with new content and a spinning wheel appears. I would like to remove the "blocking overlay with updating data.. text and spinning wheel" and let the app download and sync the json to the db in the background, so that the user could keep on interacting with the UI.

I've tried to use dispatch_async but the UI keeps being blocked until the update is done. Does anyone have any suggestions on how to achieve this?

I stripped down the code to the relevant points and added the updateData function where the ApiWrapper does the networking job.

func syncData(now: Bool) {

    var synced : Bool = false

    if ((NSUserDefaults.standardUserDefaults().objectForKey("lastSyncApp")) != nil) {
        var interval = 0
        if ((NSUserDefaults.standardUserDefaults().objectForKey("intervalSyncValue")) != nil) {
            interval = NSUserDefaults.standardUserDefaults().objectForKey("intervalSyncValue") as! Int
        }
        else{
            interval = 86400
        }
        let date = NSUserDefaults.standardUserDefaults().objectForKey("lastSyncApp") as! NSDate
        var timestamp = UInt64(floor(date.timeIntervalSince1970))
        //Create final date
        let lastsyncTimestampDate : UInt64 = timestamp + UInt64(interval)

        var nowTimestampDate = UInt64(floor(NSDate().timeIntervalSince1970))

        if ((nowTimestampDate > lastsyncTimestampDate) || now) {


                synced = true
                let formatter = NSDateFormatter()
                formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"

                //MRProgressOverlayView.showOverlayAddedTo(self.window, title: "Aggiorno dati...", mode: MRProgressOverlayViewMode.Indeterminate, animated: true, tintColor: UIColor.blackColor())

                self.downloadDate = formatter.stringFromDate(date)
                NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: Selector("updateData:"), userInfo: nil , repeats: false)



    ….}        








func updateData(timer: NSTimer!) {


    let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
    dispatch_async(dispatch_get_global_queue(priority, 0)) {
        // do some task



    var ApiWrapper = API()

    let date = self.downloadDate


            ApiWrapper.model.deleteNews()
            ApiWrapper.model.resetNewsFetch()



            //var ApiWrapper = API()

….. }

floyd0987
  • 31
  • 7
  • Where's the networking (download) in that code? I don't see it. And please, don't throw all your code at the wall like spaghetti and expect us to pick through it: find the key lines and show them. – matt Mar 05 '16 at 17:38
  • But there's nothing happening in the background there. You are deliberately staying on the main thread. Your code makes no sense and your question makes no sense. – matt Mar 05 '16 at 17:56
  • So , how can I send the updataData function to the background? – floyd0987 Mar 05 '16 at 18:00
  • You can't. Your `updateData` function makes the very same mistake: it deliberately comes back onto the main thread to do the networking. That is exactly what you need to fix. – matt Mar 05 '16 at 18:33

1 Answers1

2

I don't see where you are using a background thread in this code, but here is a really concise example of how to do this.

basically,

dispatch_async(dispatch_get_global_queue(priority, 0)) {}

will get you on the background thread, and if you need to update the UI from there, make sure you execute that code back on the main thread:

dispatch_async(dispatch_get_main_queue()) {}

Swift 4 UPDATE

DispatchQueue.global(qos: [Desired QoSClass]).async {
    // This code is executing on a background thread at 
    // your desired quality of service level

    DispatchQueue.main.async {
         // Code to be executed on the main thread here
    }
}
ackerman91
  • 549
  • 3
  • 13