I have an array of SKSpriteNode
objects that I want to persist to 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. But when I unarchive the data, the engineSize
property of the objects is reset to the default value of 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)")
}
}
}
This answer led me to try implementing encoder/decoder methods on the Car
class:
Car.swift (updated)
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? What can I do to prevent the engineSize
properties from resetting to 0 when they are restored from defaults?
UPDATE
Here is my updated Car
class as I'm trying to get it to work with rmaddy's suggestions:
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.