我有一些类型,我根据CodingKeys需要为其数据成员提供自定义名称。我想根据不同调用站点的要求,CodingKeys在将数据发送到服务器之前仅对类型的子集进行编码。所需的编码因调用站点而异,因此无需考虑默认实现。
示例类型(用于演示目的):
struct Account: Codable
{
let name: String;
var balance: Float;
mutating func set(balance: Float)
{
self.balance = balance; // verifications, etc.
}
}
struct User: Codable
{
enum CodingKeys: String, CodingKey
{
case
id = "db_id",
name = "db_name",
account
// many more keys
}
let id: Int;
let name: String;
var account: Account;
// many more data members
}
Run Code Online (Sandbox Code Playgroud)
创建实例:
var user = User(
id: 1, name: "john", account: Account(name: "checking", balance: 10_000));
Run Code Online (Sandbox Code Playgroud)
JSONEncoder按预期使用作品;它产生以下结果:
{
"db_id" : 1,
"db_name" : "john",
"account" : {
"balance" : 10000,
"name" : "checking"
}
}
Run Code Online (Sandbox Code Playgroud)
我想对User类型的子集进行编码,以便将该数据发送回服务器,以便我可以更新特定的数据字段,而不是更新类型的整个属性集。模拟使用示例:
user.account.set(balance: 15_000);
let jsonEncoding = JSONEncodeSubset.of(
user, // instance to encode
keys: [User.CodingKeys.id, User.CodingKeys.account] // data to include
);
Run Code Online (Sandbox Code Playgroud)
生成的 JSON 看起来像这样:
{
"db_id" : 1,
"account" : {
"balance" : 15000,
"name" : "checking"
}
}
Run Code Online (Sandbox Code Playgroud)
服务器端,我们现在拥有执行所需更新所需的确切数据。
另一个例子:有人为我们的用户输入了错误的名称,因此另一个更新请求如下所示:
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
);
Run Code Online (Sandbox Code Playgroud)
预期的 JSON 编码结果:
{
"db_id" : 1,
"name" : "jon"
}
Run Code Online (Sandbox Code Playgroud)
请注意,我们排除了不属于更新的信息(用户帐户)。目标是优化编码以仅包含与该特定请求相关的数据。
考虑到我有大量要更新的对象,不同的调用站点更新不同的内容,我希望有一种简洁的方法来执行编码任务。
Swift 是否为编码类型的子集提供任何此类支持CodingKeys?
此解决方案要求您encode(to:)为所有属性编写自定义内容,但一旦完成,它应该很容易使用。
这个想法是让encode(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)
}
}
}
Run Code Online (Sandbox Code Playgroud)
selectedCodingKeys是结构中的新属性
var selectedCodingKeys = [CodingKeys]()
Run Code Online (Sandbox Code Playgroud)
我们还可以添加一个特定的编码函数
mutating func encode(for codingKeys: [CodingKeys]) throws -> Data {
self.selectedCodingKeys = codingKeys
return try JSONEncoder().encode(self)
}
Run Code Online (Sandbox Code Playgroud)
然后可以像本例中那样进行解码
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)
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
637 次 |
| 最近记录: |