如何将 Codable 协议与引用类型一起使用?
How to use Codable protocol with reference types?
示例:
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
输出:
true
false
如何使用引用类型的 Codable 协议?
这种行为将来可能会改变?
https://github.com/apple/swift-evolution/blob/master/proposals/0167-swift-encoders.md
似乎编码器目前不尊重引用,而是在每次引用时保存同一对象的单独实例,这就是 ===
失败的原因。您可以将其更改为 ==
并为您的 类 实施 Equatable
,这应该可以解决此问题,或者如对问题的评论所述,使用结构。
这是 JSON 的基础,而不是 Codable。 JSON 是值的编码。它不跟踪引用;它不是格式的一部分。如果您想跟踪引用,则必须通过编码 objectIdentifier
自己将其存储在 JSON 中。然后,您需要连接具有相同标识符的事物。但这超出了 Codable 的范围,因为底层格式没有这个概念。您需要创建一些其他格式(可能使用 JSON 作为其基础值格式,就像 NSKeyedArchiver
使用 属性 列表作为其基础值格式一样)。
JSON 不是对象图存储格式;正如我所说,这是一种价值编码。如果你想要一个对象图,那就是 NSKeyedArchiver
的目的。如果你想要一个非 Cocoa 的解决方案,你需要实现一个新的 Encoder
和 Decoder
来实现与存档器相同的基本思想。这不是 JSONEncoder
的目的。但如果可能的话,我会使用 NSKeyedArchiver
;它就是为此而设计的。
请注意,SE-0167 说 NSKeyedArchiver
上有一个新的 encodeCodable
方法,可以让您将 Codable
类型与 NSCoding
类型混合(并且允许 Swift 类型参与 NSKeyedArchiver
),但我在 Xcode 9 beta 1 中看不到它。
示例:
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
输出:
true
false
如何使用引用类型的 Codable 协议?
这种行为将来可能会改变? https://github.com/apple/swift-evolution/blob/master/proposals/0167-swift-encoders.md
似乎编码器目前不尊重引用,而是在每次引用时保存同一对象的单独实例,这就是 ===
失败的原因。您可以将其更改为 ==
并为您的 类 实施 Equatable
,这应该可以解决此问题,或者如对问题的评论所述,使用结构。
这是 JSON 的基础,而不是 Codable。 JSON 是值的编码。它不跟踪引用;它不是格式的一部分。如果您想跟踪引用,则必须通过编码 objectIdentifier
自己将其存储在 JSON 中。然后,您需要连接具有相同标识符的事物。但这超出了 Codable 的范围,因为底层格式没有这个概念。您需要创建一些其他格式(可能使用 JSON 作为其基础值格式,就像 NSKeyedArchiver
使用 属性 列表作为其基础值格式一样)。
JSON 不是对象图存储格式;正如我所说,这是一种价值编码。如果你想要一个对象图,那就是 NSKeyedArchiver
的目的。如果你想要一个非 Cocoa 的解决方案,你需要实现一个新的 Encoder
和 Decoder
来实现与存档器相同的基本思想。这不是 JSONEncoder
的目的。但如果可能的话,我会使用 NSKeyedArchiver
;它就是为此而设计的。
请注意,SE-0167 说 NSKeyedArchiver
上有一个新的 encodeCodable
方法,可以让您将 Codable
类型与 NSCoding
类型混合(并且允许 Swift 类型参与 NSKeyedArchiver
),但我在 Xcode 9 beta 1 中看不到它。