NSKeyedArchiver 在 Swift 3 (Xcode 8) 中不起作用
NSKeyedArchiver does not work in Swift 3 (Xcode 8)
我已将我的项目迁移到 Swift 3,但 NSKeyedArchiver
不起作用。我在尝试像这样解码对象时实际上遇到了运行时错误:
let startDayTime = aDecoder.decodeObject(forKey: Key.startDayTime) as! Int
它在 Swift 2.2 和 Xcode 7.3 中完美运行。其他人遇到过这样的麻烦吗?
P.S。我在模拟器和设备上都有这个错误。
我使用以下方法解决了这个问题:
decodeInteger(forKey key: String)
而不是:
decodeObject(forKey key: String)
由于某些原因 AnyObject 在 Swift 3 中没有转换为 Integer,尽管它在 Swift 2.2
中转换为 Integer
这似乎只发生在 Swift 2 到 Swift 3 更新边界上,当使用 Swift 2 中的 NSKeyedArchiver
存档的 NSData blob 打开时a NSKeyedUnarchiver
in Swift 3. 我的猜测是在 Swift 2 上,Bool
和 Int
被编码为 NSNumber
,但在 Swift 3,它们被编码为原始 Bool
和 Int
类型。我相信以下测试支持这一说法:
这在 Swift 3 中有效以取消归档在 Swift 2 中编码的 Bool
,但是 returns nil
如果 Bool 在 [=] 中编码32=]3:
let visible = aDecoder.decodeObject(forKey: "visible") as? Bool
这在 Swift 3 中有效以取消存档在 Swift 3 中编码的 Bool
,但如果 Bool 在 Swift 2 中编码则崩溃:
let visible = aDecoder.decodeBool(forKey: "visible")
我的解决方案是:
let visible = aDecoder.decodeObject(forKey: "visible") as? Bool ?? aDecoder.decodeBool(forKey: "visible")
Swift 3:
我采用了双问号 (??) 方法,它的效果非常好只有一行。
如果 val 不为 nil,则解包并返回值。如果为零则 aDecoder.decodeInteger(forKey: "val")
返回:
self.val = aDecoder.decodeObject(forKey: "val") as? Int ?? aDecoder.decodeInteger(forKey: "val")
解决方法如下:
class Person: NSObject, NSCoding {
let name: String
let age: Int
required init(name: String, age: Int) {
self.name = name
self.age = age
}
required init(coder decoder: NSCoder) {
self.name = decoder.decodeObject(forKey: "name") as? String ?? ""
self.age = decoder.decodeInteger(forKey: "age")
}
func encode(with coder: NSCoder) {
coder.encode(name, forKey: "name")
coder.encode(age, forKey: "age")
}
}
使用方法:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let newPerson = Person(name: "Joe", age: 10)
var people = [Person]()
people.append(newPerson)
let encodedData = NSKeyedArchiver.archivedData(withRootObject: people)
UserDefaults.standard().set(encodedData, forKey: "people")
if let data = UserDefaults.standard().data(forKey: "people"),
myPeopleList = NSKeyedUnarchiver.unarchiveObject(with: data) as? [Person] {
myPeopleList.forEach({print( [=11=].name, [=11=].age)}) // Joe 10
} else {
print("There is an issue")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
参考:
我已将我的项目迁移到 Swift 3,但 NSKeyedArchiver
不起作用。我在尝试像这样解码对象时实际上遇到了运行时错误:
let startDayTime = aDecoder.decodeObject(forKey: Key.startDayTime) as! Int
它在 Swift 2.2 和 Xcode 7.3 中完美运行。其他人遇到过这样的麻烦吗?
P.S。我在模拟器和设备上都有这个错误。
我使用以下方法解决了这个问题:
decodeInteger(forKey key: String)
而不是:
decodeObject(forKey key: String)
由于某些原因 AnyObject 在 Swift 3 中没有转换为 Integer,尽管它在 Swift 2.2
中转换为 Integer这似乎只发生在 Swift 2 到 Swift 3 更新边界上,当使用 Swift 2 中的 NSKeyedArchiver
存档的 NSData blob 打开时a NSKeyedUnarchiver
in Swift 3. 我的猜测是在 Swift 2 上,Bool
和 Int
被编码为 NSNumber
,但在 Swift 3,它们被编码为原始 Bool
和 Int
类型。我相信以下测试支持这一说法:
这在 Swift 3 中有效以取消归档在 Swift 2 中编码的 Bool
,但是 returns nil
如果 Bool 在 [=] 中编码32=]3:
let visible = aDecoder.decodeObject(forKey: "visible") as? Bool
这在 Swift 3 中有效以取消存档在 Swift 3 中编码的 Bool
,但如果 Bool 在 Swift 2 中编码则崩溃:
let visible = aDecoder.decodeBool(forKey: "visible")
我的解决方案是:
let visible = aDecoder.decodeObject(forKey: "visible") as? Bool ?? aDecoder.decodeBool(forKey: "visible")
Swift 3:
我采用了双问号 (??) 方法,它的效果非常好只有一行。
如果 val 不为 nil,则解包并返回值。如果为零则 aDecoder.decodeInteger(forKey: "val")
返回:
self.val = aDecoder.decodeObject(forKey: "val") as? Int ?? aDecoder.decodeInteger(forKey: "val")
解决方法如下:
class Person: NSObject, NSCoding {
let name: String
let age: Int
required init(name: String, age: Int) {
self.name = name
self.age = age
}
required init(coder decoder: NSCoder) {
self.name = decoder.decodeObject(forKey: "name") as? String ?? ""
self.age = decoder.decodeInteger(forKey: "age")
}
func encode(with coder: NSCoder) {
coder.encode(name, forKey: "name")
coder.encode(age, forKey: "age")
}
}
使用方法:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let newPerson = Person(name: "Joe", age: 10)
var people = [Person]()
people.append(newPerson)
let encodedData = NSKeyedArchiver.archivedData(withRootObject: people)
UserDefaults.standard().set(encodedData, forKey: "people")
if let data = UserDefaults.standard().data(forKey: "people"),
myPeopleList = NSKeyedUnarchiver.unarchiveObject(with: data) as? [Person] {
myPeopleList.forEach({print( [=11=].name, [=11=].age)}) // Joe 10
} else {
print("There is an issue")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
参考: