3

例子:

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

4

2 回答 2

8

这是 JSON 的基础,而不是 Codable。JSON 是值的编码。它不跟踪引用;它不是格式的一部分。如果要跟踪引用,则必须自己将其存储在 JSON 中,方法是 encoding objectIdentifier。然后,您需要连接具有相同标识符的事物。但这超出了 Codable 的范围,因为底层格式没有这个概念。您需要创建一些其他格式(可能使用 JSON 作为其基础值格式,就像NSKeyedArchiver使用属性列表作为其基础值格式一样)。

JSON 不是对象图存储格式;正如我所说,这是一个值编码。如果你想要一个对象图,这就是NSKeyedArchiver目的。如果您想要一个非 Cocoa 解决方案,您将需要实现一个新的Encoder并且Decoder实现了与归档器相同的基本思想。那不是JSONEncoder目的。但如果可能的话,我会使用NSKeyedArchiver;它是为此而设计的。

请注意,SE-0167 说有一种新encodeCodable方法NSKeyedArchiver可以让您将Codable类型与NSCoding类型混合(并允许 Swift 类型参与NSKeyedArchiver),但我在 Xcode 9 beta 1 中看不到它。

于 2017-06-15T19:12:28.133 回答
1

似乎编码器当前不尊重引用,而是在每次引用时保存同一对象的单独实例,这就是===失败的原因。您可以将其更改为==Equatable为应该解决此问题的类实现,或者如对问题的评论所述,使用结构。

于 2017-06-15T19:07:30.287 回答