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: NSData
, NSString
, NSArray
, NSDictionary
, NSDate
和NSNumber
。 (在这种情况下,为什么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 ,如果出现问题,则会引发错误。
注意:您的自定义对象必须从NSObject
inheritance,否则在归档时会出现以下错误:
*** 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转换,整个工作没有问题。