问题
I am building a game using SpriteKit and Swift 4, with a number of custom classes in the SKNode family. I am trying to use the Codable protocol with them to (hypothetically) make saving the game easier. As a bit of context, here is a high level overview of the main classes in the game:
Hero class, custom SKSpriteNode, implements Codable. The Hero class, as a property, has a dictionary in the form of: [String:MapNode]
MapNode class, custom SKSpriteNode, implements Codable. The MapNode class, as a property, has an array of TileNodes like: [TileNode]
TileNode class, custom SKSpriteNode, implements codable. The TileNode class has only primitive properties.
I seem to be able to encode everything okay, and save everything to defaults, but when I go to decode a saved game, I get the following error within the MapNode class:
Thread 1: Fatal error: init(coder:) has not been implemented
On this required init:
required init?(coder aDecoder: NSCoder) {
// subclass of SKNode must implement this method
fatalError("init(coder:) has not been implemented")
}
What I do not understand is why this init is even being called at all (or why it is required) because as I understand it, it is not used by the Codable protocol at all. In the class where this required init lives (MapNode), I also have the following Codable functions:
enum CodingKeys: String, CodingKey {
case height
case width
case tileArray
}
required init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
height = try values.decode(Int.self, forKey: .height)
width = try values.decode(Int.self, forKey: .width)
let tileArrayData = try values.decode(Data.self, forKey: .tileArray)
tileArray = (NSKeyedUnarchiver.unarchiveObject(with: tileArrayData) as? [TileNode])!
self.isUserInteractionEnabled = true
self.size = CGSize(width: width, height: height)
self.name = "map"
zPosition = 5
addMapImageLayer(forMap: self)
}
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)
let tileArrayData = NSKeyedArchiver.archivedData(withRootObject: tileArray)
try container.encode(tileArrayData, forKey: .tileArray)
}
My thought was that since I am implementing Codable on everything that the code would use the Codable functions when it needed to initialize and decode Codable encoded data. What should I be doing differently?
来源:https://stackoverflow.com/questions/50916375/why-isnt-the-codable-init-being-called-instead-of-the-other-required-init