在 UserDefaults 上使用 NSKeyedArchiver 时属性重置
Properties reset when using NSKeyedArchiver on UserDefaults
我有一个包含 SKSpriteNode
个对象的数组,我想将其保存到 UserDefaults
。在下面的代码 (or see demo project on GitHub) 中,我使用 NSKeyedUnarchiver
将数组编码为数据,然后再将其设置为默认值。但是当我取消归档数据时,对象的 engineSize
属性 被重置为默认值 0.
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
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)")
}
}
}
让我尝试在 Car
class:
上实现 encoder/decoder 方法
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")
}
}
但是,这似乎不起作用。 GameScene
仍在将 engineSize
打印为 0。我是否实施了 coder/decoder 错误?我该怎么做才能防止 engineSize
属性在从默认值恢复时重置为 0?
更新
这是我更新后的 Car
class,因为我正试图让它与 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")
}
}
代码编译并运行,但 engineSize
属性 在保存为默认值时仍被重置为 0。
我设法让它工作了。以下是更新后的 GameScene
和 Car
代码文件,NSCoding
已正确实施。
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
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)")
}
}
}
更新
如果如上所示实现 init(coder aDecoder: NSCoder)
和 encode(with aCoder: NSCoder)
,您可能会注意到一些类型属性,如 color
、position
或 size
在你 archive/unarchive 他们之后被重置为他们的初始值。这是因为你现在提供了自己对这两个方法的实现,所以你不能再依赖超类来为你处理类型属性的encoding/decoding。
您现在必须为您关心的 所有 属性实现 encoding/decoding,包括您自己的自定义属性和类型的属性。例如:
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")
}
我有一个包含 SKSpriteNode
个对象的数组,我想将其保存到 UserDefaults
。在下面的代码 (or see demo project on GitHub) 中,我使用 NSKeyedUnarchiver
将数组编码为数据,然后再将其设置为默认值。但是当我取消归档数据时,对象的 engineSize
属性 被重置为默认值 0.
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
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)")
}
}
}
Car
class:
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")
}
}
但是,这似乎不起作用。 GameScene
仍在将 engineSize
打印为 0。我是否实施了 coder/decoder 错误?我该怎么做才能防止 engineSize
属性在从默认值恢复时重置为 0?
更新
这是我更新后的 Car
class,因为我正试图让它与 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")
}
}
代码编译并运行,但 engineSize
属性 在保存为默认值时仍被重置为 0。
我设法让它工作了。以下是更新后的 GameScene
和 Car
代码文件,NSCoding
已正确实施。
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
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)")
}
}
}
更新
如果如上所示实现 init(coder aDecoder: NSCoder)
和 encode(with aCoder: NSCoder)
,您可能会注意到一些类型属性,如 color
、position
或 size
在你 archive/unarchive 他们之后被重置为他们的初始值。这是因为你现在提供了自己对这两个方法的实现,所以你不能再依赖超类来为你处理类型属性的encoding/decoding。
您现在必须为您关心的 所有 属性实现 encoding/decoding,包括您自己的自定义属性和类型的属性。例如:
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")
}