Decode object in WatchKit Extension

Hello,


I am trying to send data from my iOS App to my Watch App by using the WatchConnectivity frameworks applicationContext. I am able to send and receive Strings, so the general setup seems to be alright.

Whenever I send a custom type i get an error while decoding the object from the applicationContext in my WatchKit extension. The custom type implements the NSCoding protocol and is located in my iOS App's target but linked to the WatchKitExtension's target as well. The error says

[NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class (Events.Event) for key (NS.objects); the class may be defined in source code or a library that is not linked'


Any hints? Or is my approach completly wrong to send data this way?

Thanks for any help

Replies

Hey,


The dictionary you pass to the WCSession APIs accept property list types.


if you take a look at the documentation for updateApplicationContext:error: it states that the method takes "A dictionary of property list values". The Property list documentation lists what object types are accepted.


So in your case, if you actually want to send your custom object you will have to serialize it to NSData and then put the NSData in the dictionary you pass to updateApplicationContext:error:. As an FYI; during the WWDC talk Introducing Watch Connectivity the presenters encouraged using serialization techniques that are compact, something NSKeyedArchiver is not, so best find some other means.


One option would be to "export" the object as pure property list types and then reconstruct it on the receiving side by adding methods such as:

- (instancetype)initWithPropertyListRepresentation:(NSDictionary *)plist;
- (NSDictionary *)propertyListRepresentation;

Thank you for your help.

The hint with the property list is great, i gonna try that out.

In the mean time i did some further research and found the main reason for the error message i got. As you suggested I did serialize my custom object to NSData using a NSKeyedArchiver in my iOS App. In my WatchApp i read out the NSData and deserialize it to my custom object using a NSKeyedUnarchiver. The problem there was that my NSKeyedUnarchiver was not able to deserialize a class named "Events.Event" (which is iosAppTarget.myCustomClass) since it has no access to a class with that name. It only knows the class "EventsWatchKitExtension.Event (which is watchKitExtensionTarget.myCustomClass) and so it is not able to deserialize such an object. I assume that NSKeyArchiver/Unarchiver use kind of a key/value store with a string key for target.class and a class value. Since the keys between my iOS App and the WatchKit Extensions differ, the WatchKitExtension is not able to deserialize an object which is serialized by the iOSApp.

There is a possibility to solve this issue by configuring the NSKeyedArchiver or NSKeyedUnarchiver. What I finally did is calling NSKeyedArchiver.setClassName("Event", forClass: Event.self) before serializing in my iOSApp and NSKeyedUnarchiver.setClass(Event.self, forClassName: "Event") before deserializing in my WatchKitExtension. So they both use the same key (without the target name in it) but the class from the own namespace to serialize or deserialize. This way i was finally able to serialize the custom objects in my iOS App, send it using WatchConnectivity and deserialize them again in my WatchKitExtension.

Perhaps this solution can help somebody solving some kind of serialization problems as well..

Thanks for posting your findings! It saved my days!


Do you have any updates since then? Because it sounds like a hack, though I'm very happy to continue to use this trick to keep things done. Thank you very much.