Dictionary becomes nil when trying to pass back CLLocation object to iOS app extension

落花浮王杯 提交于 2019-12-13 13:37:48

问题


I'm trying to pass a stored CLLocation object from my iOS app back to an extension (in that case: an Apple Watch extension).

For that, I'm using the recommended openParentApplication(userInfo: [NSObject : AnyObject]!, reply: (([NSObject : AnyObject]!, NSError!) -> Void)!) -> Bool function from the WKInterfaceController class in the extension code. I'm successfully receiving the request in my iOS app through the application delegate's application(application: UIApplication!, handleWatchKitExtensionRequest userInfo: [NSObject : AnyObject]!, reply: (([NSObject : AnyObject]!) -> Void)!) function.

Now, I'm trying to pass data back to the app extension using 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 this code is executed in the iOS app's context and everything is working fine. However, when the reply function gets called in the extension's context, the dictionary ultimately becomes nil.

    InterfaceController.openParentApplication(parentValues, reply: {(values, error) -> Void in
        NSLog("\(values) (err: \(error))") // echoed back to the console: "nil (err: nil)"
    })

I realised that the faulty line is this one:

                results["results"] = loc

When this line is commented, the extension successfully gets a dictionary filled with the two first items as strings ("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 a CLLocation object in my dictionary makes it all fail and become nil, but I can't understand why. What am I doing wrong?

Thanks for your help.

EDIT: per @matt's request, here's the code for getLastKnownLocation():

class func getLastKnownLocation() -> CLLocation? {
    return NSKeyedUnarchiver.unarchiveObjectWithData(NSUserDefaults(suiteName: AppHelper.appGroupName)!.dataForKey("UserLastLocation")!) as CLLocation?
}

回答1:


I read in the docs: "The contents of the dictionary must be serializable to a property list file." But a CLLocation is not serializable in this way. Presumably you must wrap it up (again) in an NSData before you stick it into the dictionary to be passed across the barrier.




回答2:


The Apple documentation states, "The contents of the dictionary must be serializable to a property list file." A CLLocation is not serializable in this way. In order to include it in the NSDictionary that is returned in this context, you need to wrap it up as an NSData object. This is straightforward. CLLocation supports NSSecureCoding, and you use an NSKeyedArchiver like this:

CLLocation *myLocationToStore = ...; // (a CLLocation object)
NSData *locationData = [NSKeyedArchiver archivedDataWithRootObject:myLocationToStore];

This can then be added to the NSDictionary, passed to the app extension, and then decoded at the other end just as simply with NSKeyedUnarchiver:

CLLocation *myStoredLocation = (CLLocation *)[NSKeyedUnarchiver unarchiveObjectWithData:locationData];

The Swift equivalent functions are:

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


来源:https://stackoverflow.com/questions/27592395/dictionary-becomes-nil-when-trying-to-pass-back-cllocation-object-to-ios-app-ext

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!