Watchkit新会话不起作用

我有两个视图控制器在我的手表扩展名。每当我打电话

[[WCSession defaultSession] sendMessage:applicationData replyHandler:^(NSDictionary *reply) {} 

我只得到第一个视图控制器的响应,并在我的第二个视图控制器的错误

 Error Domain=WCErrorDomain Code=7011 "Message reply failed." UserInfo={NSUnderlyingError=0x79f1f100 {Error Domain=WCErrorDomain Code=7010 "Payload contains unsupported type." UserInfo={NSLocalizedRecoverySuggestion=Only pass valid types., NSLocalizedDescription=Payload contains unsupported type.}}, NSLocalizedDescription=Message reply failed.} 

WCSession是在应用程序和手表extension.Anybuild议?

在WCSessionDelegate的 - session:didReceiveMessage:replyHandler:方法中, replyHandler参数被定义为[String : AnyObject]AnyObject部分是误导性的。 它只能包含一个属性列表数据types: NSDataNSStringNSArrayNSDictionaryNSDateNSNumber 。 (在这种情况下,为什么selectAnyObject是有意义的,因为这6个数据types不是从NSObject以外的公共子类inheritance的。

通常人们都提到NSCoding和NSKeyedArchiver可以解决这个问题,但是除此之外我还没有看到更多的例子/解释。

需要注意的是replyHandler字典并不关心序列化。 你可以使用NSKeyedArchiver,JSON,你自己的自定义编码等。只要字典只包含那6种数据types,replyHandler就会很开心。 否则,你会看到Payload contains unsupported type. 错误。

出于这个原因,即使myCustomObject完美地实现了NSCoding协议,也不能像这样调用replyHandler(["response": myCustomObject)

编码select总结:

  • NSCoding:主要优点是,当你解压时,它会自动find正确的类并为你实例化它,包括子图中的任何对象。
  • JSON
  • 自定义编码:一个好处是你的对象不是强制从NSObjectinheritance,这在Swift中有时是有用的。

如果你确实使用了NSCoding,这就是它的样子:

iPhone应用程序:

 func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : AnyObject]) -> Void) { let data = NSKeyedArchiver.archivedDataWithRootObject(myCustomObject) replyHandler(["response": data]) } 

观看应用:

 WCSession.defaultSession().sendMessage([], replyHandler: { response -> Void in let myCustomObject = NSKeyedUnarchiver.unarchiveObjectWithData(response["response"]) }, errorHandler: nil ) 

请注意,如果您想在解除对象的情况下从崩溃中恢复,则需要使用新的iOS 9 API unarchiveTopLevelObjectWithData ,如果出现问题,则会引发错误。

注意:您的自定义对象必须从NSObjectinheritance,否则在归档时会出现以下错误:

*** NSForwarding:警告:对象…类“Foo”没有实现methodSignatureForSelector: – 麻烦未来无法识别的select器 – [Foo replacementObjectForKeyedArchiver:]

“有效负载包含不受支持的types”可能意味着您要在消息字典中发送自定义对象。 您将需要序列化此数据以包含仅受支持的types(NSNumber,NSDate,NSString,NSData,NSArray和NSDictionary)。

我有一个github项目,自动序列化您的自定义对象到安全的watchkit转移。 你可以在这里查看

使用NSKeyedArchiver / NSKeyedUnarchiver可以序列化任何实现NSCoding的对象。

归档:

 NSData *data = [NSKeyedArchiver archivedDataWithRootObject: entries]; 

其中entries是一个实现NSCoding的对象数组。

取消存档:

 NSArray *entries = [NSKeyedUnarchiver unarchiveObjectWithData:data]; 

NSCoding是一个有两个方法的协议,你必须这样实现。

 -(id) initWithCoder: (NSCoder *)decoder { if(self = [super init]){ self.yourpoperty = [decoder decodeObjectForKey:@"PROPERTY_KEY"]; } return self; } - (void) encodeWithCoder: (NSCoder *)encoder { [encoder encodeObject:self.yourpoperty forKey:@"PROPERTY_KEY"]; } 

我通过将字典格式的JSONstring直接发送到iPhone应用程序Appdelegate的callback方法来解决这个问题

 - (void)session:(WCSession *)session didReceiveMessage:(NSDictionary<NSString *, id> *)message replyHandler:(void(^)(NSDictionary<NSString *, id> *replyMessage))replyHandler { 

而不是将JSON字典转换为普通字典。 并将此JSON字典转换为watch viewcontroller中的普通字典callback方法

 [[WCSession defaultSession] sendMessage:applicationData replyHandler:^(NSDictionary *reply) {} 

由于我从两个不同的视图控制器在手表调用这个方法,从iPhone应用程序发送正常字典第一次看到工作正常,但由于某些原因,我得到的问题,如果我从iPhone应用程序的字典发送错误为手表的第二个视图控制器。

当意外地将超过400个数据对象传送到手表时,我看到了这个错误。 限制为20个对象修复了错误。

在我的情况下,iOS 10和XCode 8.0之前发生了什么,在我使用的watchkit应用代码中:

 let infoDictionary = ["request" : "word_detail", "word": self.word, "type": self.type] 

它的作品很受欢迎。 当我在XCode 8.0的WatchKit app 2.0模拟器中testing相同的代码时,发现watchkit连接错误显示不支持的格式信息。

经过大量的debugging,我发现它的解决scheme:

 let infoDictionary:NSDictionary = ["request" : "word_detail", "word": self.word, "type": self.type] 

我不得不把NSDictionary作为一个types转换,整个工作没有问题。