[英]Properties reset when using NSKeyedArchiver on UserDefaults
I have an array of SKSpriteNode
objects that I want to persist to UserDefaults
.我有一组
SKSpriteNode
对象,我想将它们保留到UserDefaults
。 In the code below ( or see demo project on GitHub ), I use NSKeyedUnarchiver
to encode the array as data before setting it to defaults.在下面的代码中(或查看 GitHub 上的演示项目),我使用
NSKeyedUnarchiver
将数组编码为数据,然后再将其设置为默认值。 But when I unarchive the data, the engineSize
property of the objects is reset to the default value of 0.但是当我
engineSize
数据时,对象的engineSize
属性被重置为默认值 0。
Car.swift Car.swift
import SpriteKit
class Car: SKSpriteNode {
var engineSize: Int = 0
init() {
super.init(texture: nil, color: .blue, size: CGSize(width: 100, height: 100))
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
GameScene.swift GameScene.swift
import SpriteKit
class GameScene: SKScene {
let defaults = UserDefaults.standard
var carArray = [Car]()
override func didMove(to view: SKView) {
for _ in 1...3 {
let car = Car()
car.engineSize = 2000
carArray.append(car)
}
// Save to defaults
defaults.set(NSKeyedArchiver.archivedData(withRootObject: carArray), forKey: "carArrayKey")
// Restore from defaults
let arrayData = defaults.data(forKey: "carArrayKey")
carArray = NSKeyedUnarchiver.unarchiveObject(with: arrayData!) as! [Car]
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for c in carArray {
print("Car's engine size is \(c.engineSize)")
}
}
}
This answer led me to try implementing encoder/decoder methods on the Car
class:这个答案让我尝试在
Car
类上实现编码器/解码器方法:
Car.swift (updated) Car.swift(更新)
import SpriteKit
class Car: SKSpriteNode {
var engineSize: Int = 0
init() {
super.init(texture: nil, color: .blue, size: CGSize(width: 100, height: 100))
}
required convenience public init(coder decoder: NSCoder) {
self.init()
if let engineSize = decoder.decodeObject(forKey: "engineSize") as? Int {
self.engineSize = engineSize
}
}
func encodeWithCoder(coder : NSCoder) {
coder.encode(self.engineSize, forKey: "engineSize")
}
}
However, this doesn't seem to be working.但是,这似乎不起作用。
GameScene
is still printing the engineSize
as 0. Am I implementing the coder/decoder wrong? GameScene
仍然将engineSize
打印为 0。我是否错误地实现了编码器/解码器? What can I do to prevent the engineSize
properties from resetting to 0 when they are restored from defaults?当它们从默认值恢复时,我可以做些什么来防止
engineSize
属性重置为 0?
UPDATE更新
Here is my updated Car
class as I'm trying to get it to work with rmaddy's suggestions:这是我更新的
Car
类,因为我试图让它与 rmaddy 的建议一起工作:
import SpriteKit
class Car: SKSpriteNode {
var engineSize: Int = 0
init() {
super.init(texture: nil, color: .blue, size: CGSize(width: 100, height: 100))
}
required init?(coder decoder: NSCoder) {
super.init(coder: decoder)
if let engineSize = decoder.decodeObject(forKey: "engineSize") as? Int {
self.engineSize = engineSize
}
}
func encodeWithCoder(coder : NSCoder) {
super.encode(with: coder)
coder.encode(self.engineSize, forKey: "engineSize")
}
}
The code compiles and runs but the engineSize
property is still being reset to 0 when saving to defaults.代码编译并运行,但在保存为默认值时,
engineSize
属性仍被重置为 0。
I managed to get this working.我设法让这个工作。 Here are the updated
GameScene
and Car
code files with NSCoding
properly implemented.以下是正确实现
NSCoding
的更新后的GameScene
和Car
代码文件。
Car.swift Car.swift
import SpriteKit
class Car: SKSpriteNode {
var engineSize: Int = 0
init() {
super.init(texture: nil, color: .blue, size: CGSize(width: 100, height: 100))
}
required init(coder aDecoder: NSCoder) {
engineSize = aDecoder.decodeInteger(forKey: "engineSize")
super.init(texture: nil, color: .blue, size: CGSize(width: 100, height: 100))
}
override func encode(with aCoder: NSCoder) {
aCoder.encode(engineSize, forKey: "engineSize")
}
}
GameScene.swift GameScene.swift
import SpriteKit
class GameScene: SKScene {
let defaults = UserDefaults.standard
var carArray = [Car]()
override func didMove(to view: SKView) {
for _ in 1...3 {
let car = Car()
car.engineSize = 2000
carArray.append(car)
}
defaults.set(NSKeyedArchiver.archivedData(withRootObject: carArray), forKey: "carArrayKey")
let arrayData = defaults.data(forKey: "carArrayKey")
carArray = NSKeyedUnarchiver.unarchiveObject(with: arrayData!) as! [Car]
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for c in carArray {
print("Car's engine size is \(c.engineSize)")
}
}
}
UPDATE更新
If you implement init(coder aDecoder: NSCoder)
and encode(with aCoder: NSCoder)
as shown above, you may notice that some type properties like color
, position
, or size
are being reset to their initial values after you archive/unarchive them.如果您实现
init(coder aDecoder: NSCoder)
和encode(with aCoder: NSCoder)
如上所示,您可能会注意到一些类型属性,如color
、 position
或size
在您存档/取消存档后被重置为它们的初始值。 This is because you are now providing your own implementation of these two methods, so you can no longer rely on the superclass to handle the encoding/decoding of the type properties for you.这是因为您现在提供了这两个方法的自己的实现,因此您不能再依赖超类来为您处理类型属性的编码/解码。
You must now implement the encoding/decoding for all properties that you care about, both your own custom properties and the type's properties.您现在必须为您关心的所有属性实现编码/解码,包括您自己的自定义属性和类型的属性。 For example:
例如:
required init(coder aDecoder: NSCoder) {
super.init(texture: nil, color: .blue, size: CGSize(width: 100, height: 100))
engineSize = aDecoder.decodeInteger(forKey: "engineSize")
self.position = aDecoder.decodeCGPoint(forKey: "position")
self.alpha = aDecoder.decodeObject(forKey: "alpha") as! CGFloat
self.zPosition = aDecoder.decodeObject(forKey: "zPosition") as! CGFloat
self.name = aDecoder.decodeObject(forKey: "name") as! String?
self.colorBlendFactor = aDecoder.decodeObject(forKey: "colorBlendFactor") as! CGFloat
self.color = aDecoder.decodeObject(forKey: "color") as! UIColor
self.size = aDecoder.decodeCGSize(forKey: "size")
self.texture = aDecoder.decodeObject(forKey: "texture") as! SKTexture?
}
override func encode(with aCoder: NSCoder) {
aCoder.encode(engineSize, forKey: "engineSize")
aCoder.encode(self.position, forKey: "position")
aCoder.encode(self.alpha, forKey: "alpha")
aCoder.encode(self.zPosition, forKey: "zPosition")
aCoder.encode(self.name, forKey: "name")
aCoder.encode(self.colorBlendFactor, forKey: "colorBlendFactor")
aCoder.encode(self.color, forKey: "color")
aCoder.encode(self.size, forKey: "size")
aCoder.encode(self.texture, forKey: "texture")
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.