Swift 编码:多种 .encode 策略?

huangapple go评论55阅读模式
英文:

Swift encoding: multiple .encode strategeis?

问题

class TestModel {
enum CodingKeys: String, CodingKey {
case someKey = "some_key"
case otherKey = "other_key"
case thirdKey = "third_key"
case apiID = "id"
// ... lots of other keys
}

func encode(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    try container.encode(someKeyValue, forKey: .someKey)
    try container.encode(otherKeyValue, forKey: .otherKey)
    try container.encode(thirdKeyValue, forKey: .thirdKey)
    // ... lots of other encoded fields
}

}

上述代码是一个名为 TestModel 的模型,用于将数据编码为 JSON 以发送到 API。但有时我希望向不同的终端发送请求,仅更新单个属性。更新始终针对相同的属性。目前,我在 encode() 中发送所有数据,这会导致大量的带宽浪费。

我相信有一种简单的方法可以做到这一点,但文档/谷歌/stackoverflow 并没有提供有用的信息。所以,您对如何创建一个类似下面的第二个编码策略并调用它有什么想法吗?

func encodeForUpdate(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    try container.encode(apiID, forKey: .apiID)
    try container.encode(justOneValueToUpdate, forKey: .someKey)
}
英文:

I have a model TestModel that encodes data to JSON to send to an API. It looks like this:

// Called by: JSONEncoder().encode(testModelObject)

class TestModel {
   enum CodingKeys: String, CodingKey {
        case someKey = "some_key"
        case otherKey = "other_key"
        case thirdKey = "third_key"
        case apiID = "id"
        // ... lots of other keys
   }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(someKeyValue, forKey: .someKey)
        try container.encode(otherKeyValue, forKey: .otherKey)
        try container.encode(thirdKeyValue, forKey: .thirdKey)
        // ... lots of other encoded fields
    }
}

The above works fine, however sometimes I wish to send a request to a different endpoint that updates just a single attribute. The update is always going to be for the same attribute. At present I'm sending through all data in encode(), which equals a lot of wasted bandwidth.

I'm sure there's an easy way to do this, but docs/google/stackoverflow aren't proving helpful. So: any thoughts on how to create a second encoding strategy along the lines of the below and call it?

func encodeForUpdate(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    try container.encode(apiID, forKey: .apiID)
    try container.encode(justOneValueToUpdate, forKey: .someKey)
}

答案1

得分: 2

需要有一个名为encode(to encoder: Encoder)的单一函数,但您可以通过使用特定的CodingKey枚举来解决这个问题。

enum SimpleCodingKeys: String, CodingKey {
    case thirdKey = "third_key"
    case apiID = "id"
}

然后使用JSONEncoderuserInfo属性来告诉何时使用这个第二个枚举。首先,我们需要一个键:

extension TestModel {
    static var useSimpleCodingKeys: CodingUserInfoKey {
        return CodingUserInfoKey(rawValue: "useSimpleCodingKeys")!
    }
}

然后调整编码函数:

func encode(to encoder: Encoder) throws {
    let useSimple = encoder.userInfo[Self.useSimpleCodingKeys] as? Bool ?? false
    if useSimple {
        var container = encoder.container(keyedBy: SimpleCodingKeys.self)
        try container.encode(apiID, forKey: .apiID)
        try container.encode(thirdKeyValue, forKey: .thirdKey)
    } else {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(someKeyValue, forKey: .someKey)
        try container.encode(otherKeyValue, forKey: .otherKey)
        try container.encode(thirdKeyValue, forKey: .thirdKey)
        // ...
    }
}

当编码时,当然要在字典中设置这个值:

let encoder = JSONEncoder()
encoder.userInfo[TestModel.useSimpleCodingKeys] = true
英文:

You need to have a single encode(to encoder: Encoder) function but you can solve this by using a specific CodingKey enum for the second strategy

enum SimpleCodingKeys: String, CodingKey {
    case thirdKey = "third_key"
    case apiID = "id"
}

and then use the userInfo property of JSONEncoder to tell when you want to use this second enum. First we need a key to use

extension TestModel {
    static var useSimpleCodingKeys: CodingUserInfoKey {
        return CodingUserInfoKey(rawValue: "useSimpleCodingKeys")!
    }
}

and then adjust the encoding function

func encode(to encoder: Encoder) throws {
    let useSimple = encoder.userInfo[Self.useSimpleCodingKeys] as? Bool ?? false
    if useSimple {
        var container = encoder.container(keyedBy: SimpleCodingKeys.self)
        try container.encode(apiID, forKey: .apiID)
        try container.encode(thirdKeyValue, forKey: .thirdKey)
    } else {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(someKeyValue, forKey: .someKey)
        try container.encode(otherKeyValue, forKey: .otherKey)
        try container.encode(thirdKeyValue, forKey: .thirdKey)
        ...
    }
}

And of course set this value in the dictionary when encoding

let encoder = JSONEncoder()
encoder.userInfo[TestModel.useSimpleCodingKeys] = true

huangapple
  • 本文由 发表于 2023年2月6日 05:45:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/75355737.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定