0

我有一组SKSpriteNode要坚持的对象UserDefaults。在下面的代码中(或参见 GitHub 上的演示项目),我使用NSKeyedUnarchiver将数组编码为数据,然后再将其设置为默认值。但是当我取消归档数据时,engineSize对象的属性被重置为默认值 0。

汽车.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类上实现编码器/解码器方法:

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当属性从默认值恢复时,我可以做些什么来防止属性重置为 0?

更新

这是我更新的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")
    }
}

代码编译并运行,但engineSize在保存为默认值时该属性仍被重置为 0。

4

1 回答 1

-1

我设法让这个工作。这是正确实施的更新GameSceneCar代码文件。NSCoding

汽车.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)如上所示,您可能会注意到某些类型属性,如colorpositionsize在您归档/取消归档它们后被重置为其初始值。这是因为您现在提供了您自己的这两种方法的实现,因此您不能再依赖超类来为您处理类型属性的编码/解码。

您现在必须为您关心的所有属性实现编码/解码,包括您自己的自定义属性和类型的属性。例如:

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")
}
于 2018-01-11T11:04:36.833 回答