swift - 在 swift iOS 中出现意外值时,如何将 nil 设置为可编码枚举

标签 swift enums codable

我正在使用 Codable对于我的 WebRequest 响应,它返回一些预定义的字符串或数字。所以,我正在使用枚举。但是当一些意外的值到达 Response 时,我的 Codable 无法解码。
这里有一些代码以便更好地理解。

class WebUser: Codable, Equatable {
    static func == (lhs: WebUser, rhs: WebUser) -> Bool {
        return lhs.id == rhs.id
    }
    ...
    var mobileNumberPrivacy: CommonPrivacyOption?
    var emailPrivacy: CommonPrivacyOption?
    var dobPrivacy: CommonPrivacyOption?
    ...
}

enum CommonPrivacyOption: Int, CaseIterable, Codable {
    case privacyOnlyMe = 1, privacyPublic, privacyFriends, privacyFriendsOfFriends

    //Does not help this optional init function
    /*init?(rawValue: Int) {
        switch rawValue {
            case 1: self = .privacyOnlyMe
            case 2: self = .privacyPublic
            case 3: self = .privacyFriends
            case 4: self = .privacyFriendsOfFriends
            default: return nil
        }
    }*/

}
但有时我从 WebServer 得到,0 表示 dobPrivacy那时我得到 DecodingError.dataCorrupted上下文异常 Cannot initialize CommonPrivacyOption from invalid Int value 0当我获得其他值时,我希望 dobPrivacy 为零,然后是 1/2/3/4。
编辑:
let dict1 = [
    "id": 2,
    "mobileNumberPrivacy": 3,
    "emailPrivacy": 4,
    "dobPrivacy": 0 // Works perfectly with 1
]
do {
    let data1 = try JSONSerialization.data(withJSONObject: dict1, options: .prettyPrinted)
    let user1 = try JSONDecoder().decode(WebUser.self, from: data1)
    print("User1 created")
}
catch DecodingError.dataCorrupted(let context) {
    print(context.codingPath)
    print(context.debugDescription)
}
catch {
    print(error.localizedDescription)
}
我将这个相同的 Codable WebUser 对象用于配置文件详细信息、搜索用户等。
因此,有时 WebRequest 的响应中可能不会再出现一个键。

最佳答案

我建议编写一个属性包装器来为您处理这个问题。
具体来说,让我们编写一个名为 NilOnDecodingError 的属性包装器。变成任何 DecodingError进入 nil .
这是NilOnDecodingError的声明:

@propertyWrapper
public struct NilOnDecodingError<Wrapped> {
    public init(wrappedValue: Wrapped?) {
        self.wrappedValue = wrappedValue
    }

    public var wrappedValue: Wrapped?
}
我们已将其定义为包装任何类型,并存储 Optional .
现在我们可以符合 DecodableWrapped类型是 Decodable :
extension NilOnDecodingError: Decodable where Wrapped: Decodable {
    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        do {
            wrappedValue = .some(try container.decode(Wrapped.self))
        } catch is DecodingError {
            wrappedValue = nil
        }
    }
}
我们可能还希望它是 EncodableWrapped类型是 Encodable :
extension NilOnDecodingError: Encodable where Wrapped: Encodable {
    public func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        if let value = wrappedValue {
            try container.encode(value)
        } else {
            try container.encodeNil()
        }
    }
}
现在我们可以包装 WebUser 的适当字段:
class WebUser: Codable {
    let id: String

    @NilOnDecodingError
    var mobileNumberPrivacy: CommonPrivacyOption?

    @NilOnDecodingError
    var emailPrivacy: CommonPrivacyOption?

    @NilOnDecodingError
    var dobPrivacy: CommonPrivacyOption?
}
为了测试,我们要打印解码用户的字段:
extension WebUser: CustomStringConvertible {
    var description: String {
        return """
        WebUser(
            id: \(id),
            mobileNumberPrivacy: \(mobileNumberPrivacy.map { "\($0)" } ?? "nil"),
            emailPrivacy: \(emailPrivacy.map { "\($0)" } ?? "nil")),
            dobPrivacy: \(dobPrivacy.map { "\($0)" } ?? "nil")))
        """
    }
}
现在我们可以试一试:
let json = """
{
    "id": "mrugesh",
    "mobileNumberPrivacy": 1,
    "emailPrivacy": 2,
    "dobPrivacy": 1000
}
"""

let user = try! JSONDecoder().decode(WebUser.self, from: json.data(using: .utf8)!)
print(user)
输出:
WebUser(
    id: mrugesh,
    mobileNumberPrivacy: privacyOnlyMe,
    emailPrivacy: privacyPublic),
    dobPrivacy: nil))

关于swift - 在 swift iOS 中出现意外值时,如何将 nil 设置为可编码枚举,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68021019/

相关文章:

ios - 如何在 Swift Struct 中存储多个回溯日期?

ios - 文本标签未根据 ScrollView SwiftUI 中的字符串扩展

ios - Coredata 轻量级迁移丢失数据

parameters - 如何更改枚举中的参数值(Swift)

python - @unique 装饰器在 python 中有什么作用?

ios - 带字典的 Swift 4 Codable 数组具有 String 和 Array 的值

ios - 尝试像在函数中一样将字典作为参数传递

ios - 在 Swift 中将多个 UIButton 添加到多个 UIView

ios - 如何显示读取 "Today, 14 April"的日期?

java - 创建字符串枚举的最佳方法?