fab*_*ian 26 ios swift watchkit
我正在尝试向我的Watchkit扩展发送"类",但是我收到此错误.
*由于未捕获的异常'NSInvalidUnarchiveOperationException'终止应用程序,原因:'* - [NSKeyedUnarchiver decodeObjectForKey:]:无法解码类的对象(MyApp.Person)
存档和取消存档在iOS应用程序上运行良好,但在与watchkit扩展程序通信时无效.怎么了?
InterfaceController.swift
let userInfo = ["method":"getData"]
WKInterfaceController.openParentApplication(userInfo,
reply: { (userInfo:[NSObject : AnyObject]!, error: NSError!) -> Void in
println(userInfo["data"]) // prints <62706c69 7374303...
if let data = userInfo["data"] as? NSData {
if let person = NSKeyedUnarchiver.unarchiveObjectWithData(data) as? Person {
println(person.name)
}
}
})
Run Code Online (Sandbox Code Playgroud)
AppDelegate.swift
func application(application: UIApplication!, handleWatchKitExtensionRequest userInfo: [NSObject : AnyObject]!,
reply: (([NSObject : AnyObject]!) -> Void)!) {
var bob = Person()
bob.name = "Bob"
bob.age = 25
reply(["data" : NSKeyedArchiver.archivedDataWithRootObject(bob)])
return
}
Run Code Online (Sandbox Code Playgroud)
Person.swift
class Person : NSObject, NSCoding {
var name: String!
var age: Int!
// MARK: NSCoding
required convenience init(coder decoder: NSCoder) {
self.init()
self.name = decoder.decodeObjectForKey("name") as! String?
self.age = decoder.decodeIntegerForKey("age")
}
func encodeWithCoder(coder: NSCoder) {
coder.encodeObject(self.name, forKey: "name")
coder.encodeInt(Int32(self.age), forKey: "age")
}
}
Run Code Online (Sandbox Code Playgroud)
agy*_*agy 55
在Swift类上使用
@objc(
name)
属性时,该类在Objective-C中可用,没有任何命名空间.因此,将可归档的Objective-C类迁移到Swift时,此属性也很有用.由于归档对象将其类的名称存储在归档中,因此应使用@objc(
name)
属性指定与Objective-C类相同的名称,以便旧的归档可以由新的Swift类取消归档.
通过添加注释@objc(name)
,即使我们只使用Swift,也会忽略命名空间.让我们来证明一下.想象一下目标A
定义了三个类:
@objc(Adam)
class Adam:NSObject {
}
@objc class Bob:NSObject {
}
class Carol:NSObject {
}
Run Code Online (Sandbox Code Playgroud)
如果目标B调用这些类:
print("\(Adam().classForCoder)")
print("\(Bob().classForCoder)")
print("\(Carol().classForCoder)")
Run Code Online (Sandbox Code Playgroud)
输出将是:
Adam
B.Bob
B.Carol
Run Code Online (Sandbox Code Playgroud)
但是,如果目标A调用这些类,结果将是:
Adam
A.Bob
A.Carol
Run Code Online (Sandbox Code Playgroud)
要解决您的问题,只需添加@objc(name)指令:
@objc(Person)
class Person : NSObject, NSCoding {
var name: String!
var age: Int!
// MARK: NSCoding
required convenience init(coder decoder: NSCoder) {
self.init()
self.name = decoder.decodeObjectForKey("name") as! String?
self.age = decoder.decodeIntegerForKey("age")
}
func encodeWithCoder(coder: NSCoder) {
coder.encodeObject(self.name, forKey: "name")
coder.encodeInt(Int32(self.age), forKey: "age")
}
}
Run Code Online (Sandbox Code Playgroud)
小智 30
在设置框架以使NSKeyedUnarchiver
工作正常后,我必须添加以下行.
在取消归档之前:
NSKeyedUnarchiver.setClass(YourClassName.self, forClassName: "YourClassName")
Run Code Online (Sandbox Code Playgroud)
归档之前:
NSKeyedArchiver.setClassName("YourClassName", forClass: YourClassName.self)
Run Code Online (Sandbox Code Playgroud)
Jac*_*ack 15
注:虽然这个答案的信息是正确的,方法更好的答案是@agy下面的一个.
这是由编译器创建导致MyApp.Person
与MyAppWatchKitExtension.Person
同一类.这通常是由两个目标共享同一个类而不是创建共享框架引起的.
两个修复:
正确的解决方法是提取Person
到框架中.主app和watchkit扩展都应该使用框架并将使用相同的*.Person
类.
解决方法是NSDictionary
在保存并传递之前将类序列化为Foundation对象(如).这NSDictionary
将是应用程序和扩展程序的代码和解码.这样做的一个好方法是实现RawRepresentable
协议Person
.
Au *_*Ris 10
我有类似的情况,我的应用程序使用我的Core
框架,我保留所有模型类.例如,我UserProfile
使用NSKeyedArchiver
和存储和检索对象NSKeyedUnarchiver
,当我决定移动所有类以MyApp
NSKeyedUnarchiver
开始抛出错误时,因为存储的对象与unarchiver 一样,Core.UserProfile
并且不像MyApp.UserProfile
预期的那样.我如何解决它是创建一个子类NSKeyedUnarchiver
和覆盖classforClassName
函数:
class SKKeyedUnarchiver: NSKeyedUnarchiver {
override open func `class`(forClassName codedName: String) -> Swift.AnyClass? {
let lagacyModuleString = "Core."
if let range = codedName.range(of: lagacyModuleString), range.lowerBound.encodedOffset == 0 {
return NSClassFromString(codedName.replacingOccurrences(of: lagacyModuleString, with: ""))
}
return NSClassFromString(codedName)
}
}
Run Code Online (Sandbox Code Playgroud)
然后添加@objc(name)
到需要归档的类中,如此处的一个答案所示.
并称之为:
if let unarchivedObject = SKKeyedUnarchiver.unarchiveObject(withFile: UserProfileServiceImplementation.archiveURL.path) as? UserProfile {
currentUserProfile = unarchivedObject
}
Run Code Online (Sandbox Code Playgroud)
它工作得很好.
解决方案NSKeyedUnarchiver.setClass(YourClassName.self, forClassName: "YourClassName")
之所以不适合我,是因为它不适用于嵌套对象,例如何时UserProfile
有var address: Address
.Unarchiver将会成功,UserProfile
但是当它更深入时会失败Address
.
而@objc(name)
单独的解决方案没有为我做的原因是因为我没有从OBJ-C转移到Swift,所以问题不是UserProfile
- > MyApp.UserProfile
而是Core.UserProfile
- > MyApp.UserProfile
.
归档时间: |
|
查看次数: |
10625 次 |
最近记录: |