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?
}

      

+3


source to share


2 answers


I read in the docs: "The contents of the dictionary must be serializable to a property list file." But CLLocation is not serialized this way. Presumably, you have to wrap it (again) in NSData before inserting it into a dictionary that needs to go through the barrier.



+4


source


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];

      

Swift equivalent functions :

class func archivedDataWithRootObject(_ rootObject: AnyObject) -> NSData]
class func unarchiveObjectWithData(_ data: NSData) -> AnyObject?

      

+2


source







All Articles