In WCSessionDelegate's - session:didReceiveMessage:replyHandler:
method, the replyHandler
argument is defined as [String : AnyObject]
. The AnyObject
portion is misleading. It can only contain a property list data type: NSData
, NSString
, NSArray
, NSDictionary
, NSDate
, and NSNumber
. (Under these circumstances, it makes sense why AnyObject
was chosen, since those 6 data types do not inherit from a common subclass besides NSObject
.)
Usually people mention that NSCoding and NSKeyedArchiver can resolve the issue, but I haven't seen more examples/explanations beyond that.
The thing to note is that the replyHandler
dictionary doesn't care about serialization. You could use NSKeyedArchiver, JSON, your own custom encoding, etc. So long as the dictionary only contains those 6 data types replyHandler will be happy. Otherwise you'll see the Payload contains unsupported type.
error.
For this reason, you can never call the reply handler like so: replyHandler(["response": myCustomObject)
, even if myCustomObject
implements the NSCoding
protocol perfectly.
Summary of encoding choices:
- NSCoding: The main advantage is that when you unarchive, it'll automatically find the correct class and instantiate it for you including any objects in its subgraph.
- JSON
- Custom encoding: One advantage is that your object is not forced to inherit from NSObject, which is sometimes helpful in Swift.
If you do use NSCoding, this is what it'll look like:
iPhone App:
func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : AnyObject]) -> Void) {
let data = NSKeyedArchiver.archivedDataWithRootObject(myCustomObject)
replyHandler(["response": data])
}
Watch App:
WCSession.defaultSession().sendMessage([],
replyHandler: {
response -> Void in
let myCustomObject = NSKeyedUnarchiver.unarchiveObjectWithData(response["response"])
}, errorHandler: nil
)
Note that if you want to recover from a crash when unarchiving objects, you'll need to use the new iOS 9 API, unarchiveTopLevelObjectWithData, which throws an error if there was a problem.
Note: Your custom object must inherit from NSObject
, otherwise you'll get the following error when archiving:
*** NSForwarding: warning: object ... of class 'Foo' does not implement methodSignatureForSelector: -- trouble ahead
Unrecognized selector -[Foo replacementObjectForKeyedArchiver:]