Dictionary becomes null when trying to pass CLLocation object to iOS app extension
I am trying to pass a saved object CLLocation
from my iOS app back to an extension (in this case: an Apple Watch extension).
To do this, I use the recommended function openParentApplication(userInfo: [NSObject : AnyObject]!, reply: (([NSObject : AnyObject]!, NSError!) -> Void)!) -> Bool
from class WKInterfaceController
to extension code. I am successfully receiving the request in my iOS app via the app delegate feature application(application: UIApplication!, handleWatchKitExtensionRequest userInfo: [NSObject : AnyObject]!, reply: (([NSObject : AnyObject]!) -> Void)!)
.
Now I am trying to pass data back to my application extension with this code:
var results = [NSObject: AnyObject]()
if let loc = getLastKnownLocation() {
results["hasLoc"] = "yes"
results["locStr"] = "\(loc)"
results["results"] = loc // at this point, loc is actually a valid CLLocation object
}
reply(results)
All of this code is being executed in the context of the iOS app and everything works fine. However, when the function reply
is called in the context of an extension, the dictionary eventually becomes nil
.
InterfaceController.openParentApplication(parentValues, reply: {(values, error) -> Void in
NSLog("\(values) (err: \(error))") // echoed back to the console: "nil (err: nil)"
})
I figured out that the faulty line is this:
results["results"] = loc
When this line is commented out, the expansion has been gaining a dictionary filled with the first two elements in the form of lines ( "hasLoc"
and "locStr"
):
[locStr: Optional(<+37.33756323,-122.04115699> +/- 10.00m (speed 5.00 mps / course 272.00) @ 21/12/2014 19:20:05 heure normale dβEurope centrale), hasLoc: yes] (err: nil)
So it seems like inserting an object CLLocation
into my dictionary makes everything fail and becomes nil
, but I can't figure out why. What am I doing wrong?
Thank you for your help.
EDIT: For @matt's request, here's the code for getLastKnownLocation()
:
class func getLastKnownLocation() -> CLLocation? {
return NSKeyedUnarchiver.unarchiveObjectWithData(NSUserDefaults(suiteName: AppHelper.appGroupName)!.dataForKey("UserLastLocation")!) as CLLocation?
}
source to share
Apple's documentation says, "The contents of the dictionary must be serializable to a property list file." So CLLocation is not serializable. To include it in the NSDictionary that is returned in this context, you need to wrap it as an NSData object. It's simple. CLLocation supports NSSecureCoding and you use NSKeyedArchiver like this:
CLLocation *myLocationToStore = ...; // (a CLLocation object)
NSData *locationData = [NSKeyedArchiver archivedDataWithRootObject:myLocationToStore];
It can then be added to the NSDictionary, passed to the application extension, and then decoded on the other end just as easily with NSKeyedUnarchiver:
CLLocation *myStoredLocation = (CLLocation *)[NSKeyedUnarchiver unarchiveObjectWithData:locationData];
class func archivedDataWithRootObject(_ rootObject: AnyObject) -> NSData]
class func unarchiveObjectWithData(_ data: NSData) -> AnyObject?
source to share