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 作为类型转换,整个过程就没有问题了。
我的手表里有两个视图控制器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 作为类型转换,整个过程就没有问题了。