Watchkit新会话不起作用

时间:2015-10-06 12:33:30

标签: ios objective-c watchkit watch-os-2

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

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

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

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在app和watch扩展中启动。有什么建议吗?

6 个答案:

答案 0 :(得分:12)

WCSessionDelegate's - session:didReceiveMessage:replyHandler:方法中,replyHandler参数定义为[String : AnyObject]AnyObject部分具有误导性。它只能包含property list数据类型:NSData, NSString, NSArray, NSDictionary, NSDate, and NSNumber。 (在这种情况下,为什么选择AnyObject是有道理的,因为除了NSObject之外,这6种数据类型不会从公共子类继承。)

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

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

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

编码选择摘要:

  • NSCoding:主要优点是当你取消归档时,它会自动找到正确的类并为你实例化它,包括其子图中的任何对象。
  • JS​​ON
  • 自定义编码:一个优点是您的对象不会被强制从NSObject继承,这在Swift中有时很有帮助。

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

iPhone App:

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,如果出现问题则会引发错误。

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

  

*** NSForwarding:警告:类'Foo'的对象...没有实现methodSignatureForSelector: - 提前出现问题   无法识别的选择器 - [Foo replacementObjectForKeyedArchiver:]

答案 1 :(得分:7)

" Payload包含不受支持的类型"可能意味着您要在消息字典中发送自定义对象。您需要序列化此数据以仅包含受支持的类型(NSNumber,NSDate,NSString,NSData,NSArray和NSDictionary)。

我有一个github项目,可以自动将自定义对象序列化为安全对象以进行watchkit传输。您可以查看here

答案 2 :(得分:2)

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

归档:

GrantResourceOwnerCredentials

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

取消归档:

NSData *data = [NSKeyedArchiver archivedDataWithRootObject: entries];

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

NSArray *entries = [NSKeyedUnarchiver unarchiveObjectWithData:data];

答案 3 :(得分:1)

我通过将字典格式的JSON字符串直接发送到iPhone应用程序Appdelegate的回调方法来解决它

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

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

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

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

答案 4 :(得分:0)

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

答案 5 :(得分:0)

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

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

它很有效。 当我在XCode 8.0的WatchKit app 2.0模拟器中测试相同的代码时,我发现watchkit连接错误显示不支持的格式消息。

经过大量调试后,我找到了解决方案:

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

我不得不把NSDictionary作为一个类型转换,整个过程没有问题。