Watchkit 新会话不起作用

Watchkit new session does not work

我的手表里有两个视图控制器extension.Whenever我调用

[[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 在应用程序和手表中启动 extension.Any 建议?

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

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

我通过将 JSON 字典格式的字符串直接发送到 iPhone app Appdelegate

的回调方法来解决它
- (void)session:(WCSession *)session didReceiveMessage:(NSDictionary<NSString *, id> *)message replyHandler:(void(^)(NSDictionary<NSString *, id> *replyMessage))replyHandler {

而不是将 JSON 词典转换为普通词典。 并在手表 viewcontroller 回调方法

中将此 JSON 字典转换为普通字典
[[WCSession defaultSession] sendMessage:applicationData
                           replyHandler:^(NSDictionary *reply) {}

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

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

使用 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"];
}

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。 (在这种情况下,为什么选择 AnyObject 是有道理的,因为除了 NSObject 之外,这 6 种数据类型没有继承自公共子 class。)

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

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

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

编码选择总结:

  • NSCoding:主要优点是当您取消存档时,它会自动找到正确的 class 并为您实例化它,包括其子图中的任何对象。
  • JSON
  • 自定义编码:一个优点是您的对象不会被强制继承自 NSObject,这有时在 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,如果有问题。

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

*** NSForwarding: warning: object ... of class 'Foo' does not implement methodSignatureForSelector: -- trouble ahead Unrecognized selector -[Foo replacementObjectForKeyedArchiver:]

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

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

而且效果很好。 当我通过 XCode 8.0 在 WatchKit 应用程序 2.0 模拟器中测试相同的代码时,我发现 watchkit 连接错误显示不支持的格式消息。

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

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

我只需要将 NSDictionary 作为类型转换,整个过程就没有问题了。