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

如何使用NSCoding编码解码Hashable类型的Swift枚举?

为带关联值的Hashable枚举实现NSCoding

你的问题核心在于ItemCatalog是带关联值的枚举,它本身未实现NSCoding,直接编码枚举实例会崩溃;而用hashValue编码完全不可行——哈希值不具备唯一性,也无法反向还原枚举的具体case和关联值。

正确的做法是拆分枚举的case类型和关联值分别编码,解码时再根据存储的信息重构枚举实例。以下是完整的实现示例:

假设你持有ItemCatalog的类是Item(如果是其他类,只需对应修改属性名):

class Item: NSObject, NSCoding {
    let catalogCode: ItemCatalog
    
    init(itemCatalogCode: ItemCatalog) {
        self.catalogCode = itemCatalogCode
        super.init()
    }
    
    // MARK: - NSCoding 编码实现
    func encode(with aCoder: NSCoder) {
        switch catalogCode {
        case .sword(let sword):
            // 编码case类型标识和关联值的rawValue
            aCoder.encode("sword", forKey: "caseType")
            aCoder.encode(sword.rawValue, forKey: "associatedValue")
        case .shield(let shield):
            aCoder.encode("shield", forKey: "caseType")
            aCoder.encode(shield.rawValue, forKey: "associatedValue")
        case .armor(let armor):
            aCoder.encode("armor", forKey: "caseType")
            aCoder.encode(armor.rawValue, forKey: "associatedValue")
        }
    }
    
    // MARK: - NSCoding 解码实现
    required init?(coder aDecoder: NSCoder) {
        // 读取存储的case类型和关联值
        guard let caseType = aDecoder.decodeObject(forKey: "caseType") as? String,
              let rawValue = aDecoder.decodeObject(forKey: "associatedValue") as? String else {
            return nil
        }
        
        // 根据case类型重构枚举实例
        switch caseType {
        case "sword":
            guard let sword = Swords(rawValue: rawValue) else { return nil }
            catalogCode = .sword(sword)
        case "shield":
            guard let shield = Shields(rawValue: rawValue) else { return nil }
            catalogCode = .shield(shield)
        case "armor":
            guard let armor = Armors(rawValue: rawValue) else { return nil }
            catalogCode = .armor(armor)
        default:
            return nil
        }
        
        super.init()
    }
}

关键说明

  1. 编码逻辑:

    • 用字符串(如sword/shield/armor)标记当前枚举的case类型,确保解码时能区分不同分支
    • 利用子枚举的rawValue(因为它们都是String类型枚举)存储关联值,String是NSCoder原生支持的可编码类型
  2. 解码逻辑:

    • 先读取case类型和关联值的rawValue,做安全类型转换避免崩溃
    • 根据case类型尝试将rawValue转换为对应的子枚举,校验失败则返回nil(符合init?(coder:)的可失败要求)
    • 最后用验证后的子枚举重构ItemCatalog实例

为什么之前的方法不行

  • 直接编码catalogCode:ItemCatalog不是NSObject也未实现NSCoding,NSCoder无法直接处理自定义枚举类型
  • 编码hashValue:哈希值仅用于哈希表快速查找,不保证唯一,且无法反向推导枚举的具体case和关联值,完全无法完成可靠的解码

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 10:36:33