Search code examples
iosswiftwatchkit

CLLocation is not submitted to iPhone


I have a question concerning the WCSession transferUserInfo method. When I try to send a CLLocation object from the Apple Watch to the owning iPhone, the corresponding receive method is never called. The code on the watch side looks like follows (shortened of course):

class InterfaceController: WKInterfaceController, WCSessionDelegate, CLLocationManagerDelegate {

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        if WCSession.default.activationState == .activated {
            let userInformation = ["MyLocation" : locations.last] as [String : Any]
            WCSession.default.transferUserInfo(userInformation)
        }
        else {
            os_log("Can not send session data", type: .error)
        }
}

}

The iPhone counterpart code:

class TableViewController: UITableViewController, WCSessionDelegate {

func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any] = [:]) {        
        let location = userInfo["MyLocation"] as? CLLocation
        if location == nil {
            os_log("Location not found", type: .error)
        }

        os_log("RX DATA : %@", location.description)
}

}

When I replace the location object by a string, everything works as expected. The string will be delivered to the iPhone.

Why is the CLLocation object not delivered but the string is? How can I configure XCode to show me the error/reason? Currently nothing happens, not even an error is shown.

Thank you


Solution

  • The user info dictionary only accepts property list types.

    CLLocation isn't one, but Data is and CLLocation implements NSCoding so you can use a keyed archiver/unarchiver to convert it to Data and back.

    Convert it to data on the watch:

    if let location = locations.last {
        let data = NSKeyedArchiver.archivedData(withRootObject: location)
        // put the data in your user info and send it along
    }
    

    Then convert it back to a location on the phone:

    if let data = userInfo["MyLocation"] as? Data,
        let location = NSKeyedUnarchiver.unarchiveObject(with: data) as? CLLocation {
        // do whatever with the location
    }