Search code examples
iosswiftwatchkitapple-watchwatchos-2

WatchKit app losing data after going background - Swift


I'm passing a dictionary from my iPhone to the watch using the (watchOS 2) applicationContext method.

Inside the iPhone app:

func giveMeInfo(){
    var lastStringUsed = porkee288.storyPoints.last!
    do {
        let resultDict = ["dict": myDict]
        try WCSession.defaultSession().updateApplicationContext(resultDict)
    }  
    catch {
        print("Something wrong happened")
    }
}

Inside the watch app:

func session(session: WCSession, didReceiveApplicationContext applicationContext: [String : AnyObject]) {

    dispatch_async(dispatch_get_main_queue()) { () -> Void in

        if let retrievedDict = applicationContext["dict"] as? [String : String] {

                self.dictInsideWatch = retrievedDict     
        }
    }
}

The data is fetched by the tableview in the watchKit nicely, however, each time the app goes to the background, the data is automatically lost, which is strange because in iPhone apps dictionaries have some persistence (at least until becoming suspended).

What would you recommend to counteract this issue and keep the data from disappearing?


Solution

  • The problem you're describing is that the table doesn't show any data once you return to the watch app. Although you didn't show that specific code, it's likely due to the dictionary being blank the next time the app is opened.

    Since the application context is only received once, any property observer or method you might be using to reload the table would only fire when the data is newly arrived, not when the app is resumed.

    When your dictionary is blank, you can fall back on the receivedApplicationContext property to access the most recent received data for your table.

    A dictionary containing the last update data received from a paired and active device. (read-only)

    Use this method to access the most recently received update dictionary. The session object also sends a newly arrived dictionary to the session:didReceiveApplicationContext: method of its delegate.

    You can also persist the dictionary in NSUserDefaults to handle the case when your app has been terminated while suspended.

    You didn't show how you called loadTable() once you had the data. You definitely want to do that, once you've (received new data or) retrieved persisted data.

    if !session.receivedApplicationContext.keys.isEmpty {
        // Use most recently received dictionary
        dictInsideWatch = receivedApplicationContext["dict"]
    } else {
        // Use persisted dictionary
        dictInsideWatch = NSUserDefaults.standardUserDefaults().dictionaryForKey("dict") ?? [:]
    }
    loadTable()
    

    If you adopt this approach, make sure to persist the data (either immediately after it's received, or at the point when the app is about to move to an inactive state).