Example:
import Foundation
class Player: Codable {
let name: String
init(name: String) {
self.name = name
}
}
class Team: Codable {
let players: [Player]
let capitan: Player
init(players: [Player], capitan: Player) {
self.players = players
self.capitan = capitan
}
}
let player1 = Player(name: "p1")
let player2 = Player(name: "p2")
let team = Team(players: [player1, player2], capitan: player1)
print(team.players[0] === team.capitan) // true
let encoder = JSONEncoder()
let data = try encoder.encode(team)
let decoder = JSONDecoder()
let team2 = try decoder.decode(Team.self, from: data)
print(team2.players[0] === team2.capitan) // false
Output:
true
false
How to use Codable protocol with reference types?
The behavior may change in the future? https://github.com/apple/swift-evolution/blob/master/proposals/0167-swift-encoders.md
This is fundamental to JSON, not Codable. JSON is an encoding of values. It does not keep track of references; it's not part of the format. If you want to keep track of references, you would have to store that in the JSON yourself, by encoding objectIdentifier. You'd then need to join up things that have the same identifier. But that's beyond the scope of Codable, since the underlying format doesn't have the concept. You'd need to create some other format (perhaps that used JSON as its underlying value format, in the way that NSKeyedArchiver uses property lists as its underlying value format).
JSON isn't an object graph storage format; as I said it's a value encoding. If you want an object graph, that's what NSKeyedArchiver is for. If you want a non-Cocoa solution, you would need to implement a new Encoder and Decoder that implemented the same basic idea as the archivers. That isn't what JSONEncoder is for. But I'd use NSKeyedArchiver if possible; it's designed for this.
Note that SE-0167 says that there is a new encodeCodable method on NSKeyedArchiver that is supposed to let you intermix Codable types with NSCoding types (and allow Swift types to participate in NSKeyedArchiver), but I don't see it in Xcode 9 beta 1.
It seems like the encoder currently does not respect references and instead saves a separate instance of the same object each time it is referenced, which is why === fails. You can change it to == and implement Equatable for your classes which should fix this, or as the comment on the question states, use structs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With