我正在使用SpriteKit构建应用程序,我想将一个复杂的自定义类保存到NSUserDefaults,利用Codable协议。当我这样做时,我收到以下错误:
Cannot automatically synthesize 'Decodable' because 'SKSpriteNode' does not conform to 'Decodable'
该类如下所示(至少是具有属性的部分):
class TileNode: SKNode, Codable {
// MARK: - Class Variables
var height = 32
var width = 32
var index = 0
var row = 0
var column = 0
var tileType = ""
// These cannot be global because each tile needs its own instance of them.
var dark = SKSpriteNode()
var light = SKSpriteNode()
// MARK: - Init
override init() {
super.init()
}
init(index:Int, tex: String) {
super.init()
if tileCheck {
print("TileNode: init: creating tile with texture: \(tex).")
}
self.isUserInteractionEnabled = false
self.index = index
self.zPosition = 10
self.name = "Tile \(index)"
self.tileType = tex
}
}
所以,我的问题是,当你需要将SKSpriteNode这样的东西作为类变量时,如何在自定义对象上使用可编码协议?
答案 0 :(得分:2)
很明显,这个问题是因为SKSpriteNode
不符合Codable
协议。因此,以下步骤可使自定义类SKSpriteNode
与Codable
协议一起使用。
required init(from:)
方法将Data
转换为SKSpriteNode
encode(to:)
方法将SKSpriteNode
转换为Data
以下是样本:
class TileNode: SKNode, Codable {
var height = 32.0
var width = 32.0
var index = 0
var row = 0
var column = 0
var tileType = ""
// These cannot be global because each tile needs its own instance of them.
var dark = SKSpriteNode()
var light = SKSpriteNode()
enum CodingKeys: String, CodingKey {
case height
case width
case index
case row
case column
case tileType
case dark
case light
}
init(index:Int, tex: String) {
super.init()
if tileCheck {
print("TileNode: init: creating tile with texture: \(tex).")
}
self.isUserInteractionEnabled = false
self.index = index
self.zPosition = 10
self.name = "Tile \(index)"
self.tileType = tex
}
required init(from decoder: Decoder) throws {
super.init()
let values = try decoder.container(keyedBy: CodingKeys.self)
height = try values.decode(Double.self, forKey: .height)
width = try values.decode(Double.self, forKey: .width)
index = try values.decode(Int.self, forKey: .index)
row = try values.decode(Int.self, forKey: .row)
column = try values.decode(Int.self, forKey: .column)
tileType = try values.decode(String.self, forKey: .tileType)
let darkData = try values.decode(Data.self, forKey: .dark)
dark = NSKeyedUnarchiver.unarchiveObject(with: darkData) as? SKSpriteNode ?? SKSpriteNode()
let lightData = try values.decode(Data.self, forKey: .light)
light = NSKeyedUnarchiver.unarchiveObject(with: lightData) as? SKSpriteNode ?? SKSpriteNode()
}
required init?(coder aDecoder: NSCoder) {
// subclass of SKNode must implement this method
fatalError("init(coder:) has not been implemented")
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(height, forKey: .height)
try container.encode(width, forKey: .width)
try container.encode(index, forKey: .index)
try container.encode(row, forKey: .row)
try container.encode(column, forKey: .column)
try container.encode(tileType, forKey: .tileType)
let darkData = NSKeyedArchiver.archivedData(withRootObject: dark)
try container.encode(darkData, forKey: .dark)
let lightData = NSKeyedArchiver.archivedData(withRootObject: light)
try container.encode(lightData, forKey: .light)
}
}
<强>用法强>
在UserDefaults中编码数据并保存数据:
let node = TileNode(index: 3, tex: "Text")
node.height = 33.0
let dark = SKSpriteNode()
dark.anchorPoint = CGPoint(x: 12.3, y: 45.6)
dark.color = UIColor.red
node.dark = dark
let encoder = JSONEncoder()
do {
let encoded = try encoder.encode(node)
UserDefaults.standard.set(encoded, forKey: "Node")
} catch {
print(error.localizedDescription)
}
从UserDefaults和Decode Data中检索数据:
let docoder = JSONDecoder()
do {
let nodeData = UserDefaults.standard.object(forKey: "Node") as! Data
let node = try docoder.decode(TileNode.self, from: nodeData)
} catch {
print(error.localizedDescription)
}