Search code examples
swiftwatchos-2watchconnectivitywcsession

how to send through multiple dictionaries/ multiple 'application updates' with swift 2.2 watch connectivity


How can I send through several 'application updates' from my phone to my watch, (such as several different values from an array) with Watch Connectivity?

My application update worked successfully to send through the numberItem value from the selected cell in my table view, but I would like to also send through the userid value from the selected cell array.

Right now, it only recognizes one value, and doesn't update the other value, but displays 'please retry' as my label text.

How can I send through two or more application updates, for other additional values (such as userid, and username).

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    let numberItem = number[indexPath.row]
    print("tableview select #:")
    print(numberItem)
    do {
        try WatchSessionManager.sharedManager.updateApplicationContext(["number" : numberItem])
    } catch {
        let alertController = UIAlertController(title: "Oops!", message: "Looks like your \(numberItem) got stuck on the way! Please send again!", preferredStyle: .Alert)
        presentViewController(alertController, animated: true, completion: nil)
    }
    let uidItem = 15
    //let uidDict = ["uidValue":uidItem]
    print("the send UID is")
    //print(uidItem)
    do {
        try WatchSessionManager.sharedManager.updateApplicationContext(["uidValue" : uidItem])
    } catch {
        let alertController = UIAlertController(title: "Oops!", message: "Looks like your \(uidItem) got stuck on the way! Please send again!", preferredStyle: .Alert)
        presentViewController(alertController, animated: true, completion: nil)
    }
}

My datasource.swift file is:

    enum Item {
    case Number(String)
    case uidValue(String)
    case Unknown
}

init(data: [String : AnyObject]) {
    if let numberItem = data["number"] as? String {
        item = Item.Number(numberItem)
        print("enum item is")
        print(numberItem)
    } else if let uidItem = data["uidValue"] as? String {
        item = Item.uidValue(uidItem)
        print("enum item is")
        print(uidItem)
    } else {
        item = Item.Unknown
    }
}

and my interface controller on the watch (connected to my data labels) includes:

func dataSourceDidUpdate(dataSource: DataSource) {
   switch dataSource.item {

   // the first application update- commented out to try the 2nd update
   //case .Number(let numberItem):
    //    titleLabel.setText(numberItem)
    //    print(numberItem)

   // the second application update
   case .uidValue(let uidItem):
       uidLabel.setText(uidItem)
       print(uidItem)
   case .Unknown:
       nidLabel.setText("please retry")
   default:
    print("default")
   }
}

Solution

  • You can't send the items separately, as updateApplicationContext would have replaced any earlier application context data with the most recent data. This is briefly mentioned in two different spots in the documentation:

    This method overwrites the previous data dictionary, ...

    This method replaces the previous dictionary that was set, ...

    Naturally, Apple optimizes the whole process for energy/memory efficiency. In this case, if the earlier application context data was still in the queue to be transmitted when the second data was queued for transmission, the earlier data can be discarded to save from having to unnecessarily transmit/store it. Your watch wouldn't even have received the first data.

    Since your watch would have only received one of the two pieces of data, this explains why you'd see "please retry" when you checked the received dictionary for one key, but it only contained the data for the other key.

    How to transmit more than one item at once

    Include both items in the same dictionary, and transmit that dictionary using a single transfer.

    let data = ["number" : numberItem, "uidValue" : uidItem]
    try WatchSessionManager.sharedManager.updateApplicationContext(data)
    ...
    

    On the watch side, you simply can update the title label and uid label at the same time, instead of conditionally updating only one or the other.

    if let numberItem = data["number"] as? String {
        titleLabel.setText(numberItem)
    }
    if let uidItem = data["uidValue"] as? String {
        uidLabel.setText(uidItem)
    }