You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将CodingKeys以数组而非枚举形式传入类外函数?

问题背景与需求

我在项目中为部分类实现了自定义JSON解码,已配置常规的CodingKeys枚举并实现了自定义编码、解码函数,功能运行正常。

但我还实现了几个解码过程的便捷函数,用于捕获JSONDecoder的KeyedDecodingContainer抛出的错误并返回合理值。由于这些函数无需在不同类间变更,我希望将其移至类外,但多数示例都将编码键硬编码为类内枚举。

补充说明:成员未设为可选类型是有合理原因的——SwiftUI中无法绑定可选类型,因此无法在编辑UI中显示该结构。

待解码的User类代码

class User : Equatable, Codable
{
    var ID: String = ""
    var pw: String = ""
    var username:  String = ""
    var firstName: String = ""
    var lastName: String = ""
    var EMail: String = ""
    var phoneNbr: String = ""
    var avatarURL: String = ""
    var mediaServiceID: String = ""
    var validated: Bool = false // E-mail is confirmed.

    // Equatable
    static func == (lhs: User, rhs: User) -> Bool
    {
        return lhs.ID == rhs.ID
    }

    // Codable
    enum CodingKeys: String, CodingKey
    {
        case ID = "ID"
        case pw = "pw"
        case username = "username"
        case firstName = "firstName"
        case lastName = "lastName"
        case EMail = "EMail"
        case phoneNbr = "phoneNbr"
        case avatarURL = "avatarURL"
        case mediaServiceID = "mediaServiceID"
        case validated = "validated"
    }

    required init(from decoder: Decoder) throws
    {
        var container: KeyedDecodingContainer<CodingKeys>
        do
        {
            container = try decoder.container(keyedBy: CodingKeys.self)
        }
        
        ID =                safeStringDecode(container: container, forKey: .ID)
        pw =                safeStringDecode(container: container, forKey: .pw)
        username =          safeStringDecode(container: container, forKey: .username)
        firstName =         safeStringDecode(container: container, forKey: .firstName)
        lastName =          safeStringDecode(container: container, forKey: .lastName)
        EMail =             safeStringDecode(container: container, forKey: .EMail)
        phoneNbr =          safeStringDecode(container: container, forKey: .phoneNbr)
        avatarURL =         safeStringDecode(container: container, forKey: .avatarURL)
        mediaServiceID =    safeStringDecode(container: container, forKey: .mediaServiceID)
        validated =         safeBoolDecode(container: container, forKey: .validated)
    }

    func safeStringDecode(container: KeyedDecodingContainer<CodingKeys>, forKey: CodingKeys) -> String
    {
        var result: String
        do
        {
            result = try container.decode(String.self, forKey: forKey)
        }
        catch
        {
            result = ""
        }
        
        return result
    }
    
    func safeBoolDecode(container: KeyedDecodingContainer<CodingKeys>, forKey: CodingKeys) -> Bool
    {
        // First try int, because that's what MySQL/MariaDB return for bools.
        var result: Int
        do
        {
            result = try container.decode(Int.self, forKey: forKey)
            return result == 1
        }
        catch
        {
            // Let's see if it's a 'true'/'false' string.
            var stringResult: String
            do
            {
                stringResult = try container.decode(String.self, forKey: forKey)
                return stringResult == "true"
            }
            catch
            {
                return false
            }
        }
    }
}

核心需求与后续思考

我希望将这些safeDecode方法移至通用工具命名空间中,但这意味着无法将编码键硬编码为类内枚举,因此需要将其以数组或字典形式传入。这看似简单,但目前我尚未找到简洁的解决方案。

实现safeDecode函数的原因是:若任何值缺失或为nil,对象解码会完全失败,而这种情况在我的数据库中完全可能发生,因为这些列是可空的。若没有这些便捷函数,我原本需要为每个成员的解码尝试单独编写do/catch代码块,这极其繁琐。但我之前不知道可以用try?语法逐行捕获错误。因此现在我仅需要布尔值助手函数来处理不同数据库的布尔类型。按照建议,我将其放在了KeyedDecodingContainer扩展中。


内容的提问来源于stack exchange,提问作者Oscar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 10:34:59