我有一组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)")
}
}
}
This answer让我尝试在Car
类上实现编码器/解码器方法:
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.我是否实现了编码器/解码器错误?从默认值恢复engineSize
属性时,如何防止Car
属性重置为0?
更新
以下是我更新的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")
}
}
课程,因为我试图让它与rmaddy的建议一起使用:
engineSize
代码编译并运行,但保存为默认值时,if request.method == 'POST':
form = RegisterForm(request.POST)
if form.is_vaild():
....
else:
# don't new form
print(form.errors.as_text())
return render(request, 'users/register.html', {'register': form})
属性仍然被重置为0。
答案 0 :(得分:-1)
在与Big Nerd Ranch iOS书籍共度美好时光之后,我设法让这个有用了。以下是已正确实施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
归档/取消归档后的初始值。这是因为您现在提供了这两种方法的自己的实现,因此您不再依赖超类来处理类型属性的编码/解码。
您现在必须为您关注的所有属性实现编码/解码,包括您自己的自定义属性和类型属性。例如:
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")
}