Swift 如何通过指定编码键的子集对可编码类型进行编码?
我为一些类型提供了Swift 如何通过指定编码键的子集对可编码类型进行编码?,swift,encoding,Swift,Encoding,我为一些类型提供了CodingKeys,并根据需要为其数据成员提供自定义名称。我希望在将数据发送到服务器之前,根据不同呼叫站点的要求,仅对类型的编码键的子集进行编码。所需的编码从调用站点更改为调用站点,因此没有默认的实现需要考虑。 示例类型(用于演示): 创建实例: var user = User( id: 1, name: "john", account: Account(name: "checking", balance: 10_000));
CodingKeys
,并根据需要为其数据成员提供自定义名称。我希望在将数据发送到服务器之前,根据不同呼叫站点的要求,仅对类型的编码键的子集进行编码。所需的编码从调用站点更改为调用站点,因此没有默认的实现需要考虑。
示例类型(用于演示):
创建实例:
var user = User(
id: 1, name: "john", account: Account(name: "checking", balance: 10_000));
使用jsonecoder
可以正常工作;它产生以下结果:
{
"db_id" : 1,
"db_name" : "john",
"account" : {
"balance" : 10000,
"name" : "checking"
}
}
我想对用户
类型的一个子集进行编码,以便将该数据发送回服务器,以便更新特定的数据字段,而不是更新类型的整个属性集。模拟使用示例:
user.account.set(balance: 15_000);
let jsonEncoding = JSONEncodeSubset.of(
user, // instance to encode
keys: [User.CodingKeys.id, User.CodingKeys.account] // data to include
);
由此产生的JSON如下所示:
{
"db_id" : 1,
"account" : {
"balance" : 15000,
"name" : "checking"
}
}
在服务器端,我们现在拥有执行所需更新所需的确切数据
另一个示例:有人为我们的用户输入了错误的名称,因此另一个更新请求如下所示:
user.name = "jon"; // assume the model was modified to make this mutable
let jsonEncoding = JSONEncodeSubset.of(
user, // instance to encode
keys: [User.CodingKeys.id, User.CodingKeys.name] // only encode id & name
);
let encoder = JSONEncoder().withEncodeSubset(keysToEncode: [User.CodingKeys.id, .account])
let encoded = try encoder.encode(user)
print(String(data: encoded, encoding: .utf8)!)
// prints: {"db_id":1,"account":{"name":"checking","balance":15000}}
预期的JSON编码结果:
{
"db_id" : 1,
"name" : "jon"
}
请注意,我们排除了不属于更新的信息(用户帐户)。目标是优化编码,使其仅包含与特定请求相关的数据
考虑到我有大量的对象要更新,不同的调用站点更新不同的东西,我希望有一种简洁的方法来执行编码任务
对类型数据成员的子集进行编码可以提高编码性能/内存占用
向服务器发送较大数量的较小编码对象会更有效
Swift是否为编码类型的编码键的子集提供任何此类支持?此解决方案要求您为所有属性编写自定义编码(to:)
,但一旦完成,就应该易于使用
其思想是让只对给定数组中存在的那些属性/键进行编码(to:)
编码。因此,给出上面的示例,函数如下所示
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
for key in selectedCodingKeys {
switch key {
case .id:
try container.encode(id, forKey: .id)
case .account:
try container.encode(account, forKey: .account)
case .name:
try container.encode(name, forKey: .name)
}
}
}
selectedCodingKeys
是结构中的新属性
var selectedCodingKeys = [CodingKeys]()
我们还可以添加一个用于编码的特定函数
mutating func encode(for codingKeys: [CodingKeys]) throws -> Data {
self.selectedCodingKeys = codingKeys
return try JSONEncoder().encode(self)
}
然后解码可以像这个例子中那样进行
var user = User(id: 1, name: "John", account: Account(name: "main", balance: 100.0))
do {
let data1 = try user.encode(for: [.id, .account])
let data2 = try user.encode(for: [.id, .name])
} catch {
print(error)
}
在Joakim Danielson的基础上展开,您可以使用codingUserInfo键
将数据传递给jsonecoder
的userInfo
属性
extension CodingUserInfoKey {
static let keysToEncode = CodingUserInfoKey(rawValue: "keysToEncode")!
}
extension JSONEncoder {
func withEncodeSubset<CodingKeys>(keysToEncode: [CodingKeys]) -> JSONEncoder {
userInfo[.keysToEncode] = keysToEncode
return self
}
}
然后像这样使用它:
user.name = "jon"; // assume the model was modified to make this mutable
let jsonEncoding = JSONEncodeSubset.of(
user, // instance to encode
keys: [User.CodingKeys.id, User.CodingKeys.name] // only encode id & name
);
let encoder = JSONEncoder().withEncodeSubset(keysToEncode: [User.CodingKeys.id, .account])
let encoded = try encoder.encode(user)
print(String(data: encoded, encoding: .utf8)!)
// prints: {"db_id":1,"account":{"name":"checking","balance":15000}}
See和@Rob我了解如何在模型需要时提供自定义编码/解码映射。我特别关注编码部分;我需要根据应用程序不同部分中编码的数据动态编码。解码部分可以在上面的链接中实现,没有问题。