Ios 如何将可编码协议与引用类型一起使用?

Ios 如何将可编码协议与引用类型一起使用?,ios,swift,swift4,codable,Ios,Swift,Swift4,Codable,例如: 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.p

例如:

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
如何将可编码协议与引用类型一起使用

这种行为将来可能会改变吗?
https://github.com/apple/swift-evolution/blob/master/proposals/0167-swift-encoders.md

编码器当前似乎不尊重引用,而是在每次引用时保存同一对象的单独实例,这就是为什么
=
失败的原因。您可以将其更改为
=
,并为您的类实现
equalable
,这应该可以解决这个问题,或者作为问题的注释,使用structs。

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


JSON不是对象图存储格式;正如我所说的,这是一种值编码。如果您想要一个对象图,这就是
NSKeyedArchiver
的用途。如果您想要一个非Cocoa解决方案,您需要实现一个新的
编码器
解码器
,它实现了与架构师相同的基本思想。这不是
jsonecoder
的目的。但如果可能的话,我会使用
NSKeyedArchiver
;它就是为这个设计的


请注意,SE-0167表示,在
NSKeyedArchiver
上有一种新的
encodeCodable
方法,该方法允许
Codable
类型与
NSCoding
类型混合(并允许Swift类型参与
NSKeyedArchiver
),但是我在Xcode 9 beta 1中没有看到它。

我想在解码后得到一个精确的副本。将来,NSKeyedArchiver将支持可编码的方法。但是我想打开基于文本的存储格式(JSON)。“您需要实现一个新的编码器和解码器,它实现了与架构师相同的基本思想”-这是一个变体,如今在stdlib中不存在这样的东西。您必须找到或构建它。@rtnm现在,您可以将一个持久属性
id:UUID
添加到您的
Player
中,并将该
id
存储为您团队的
队长。然后实现您自己的
init(from:)
encode(to:)
id
和实际
Player
参考之间进行转换(首先解码所有
Player
后,您将搜索您的队长
Player
)。这是一个很好的解决办法。此外,“普拉亚船长”是一个伟大的乐队名字您可能需要
objectIdentifier
来实现这一点(而不是创建自己的
id
),但实现它需要某种自定义
编码器
/
解码器
或后处理步骤来消除重复。我需要引用类型