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()
….. }
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
}
}