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

Swift中Codable自定义对象编码崩溃问题求助

问题排查与解决方案

一、手动实现Workout Codable时崩溃的原因与解决

崩溃原因

NSKeyedArchiver是Objective-C时代的归档工具,要求归档对象必须遵循NSCoding协议(依赖OC的消息机制)。你的Exercise仅遵循Swift原生的Codable,未实现NSCoding相关方法,导致OC归档工具无法识别,触发unrecognized selector错误。

两种解决方案

方案1:让Exercise同时遵循NSCoding与Codable

如果必须使用NSKeyedArchiver,修改Exercise类:

class Exercise: NSObject, Codable, NSCoding {
    var name: String
    var duration: Int
    
    // Codable编码键
    enum CodingKeys: String, CodingKey {
        case name, duration
    }
    
    // NSCoding编码实现
    func encode(with coder: NSCoder) {
        coder.encode(name, forKey: CodingKeys.name.rawValue)
        coder.encode(duration, forKey: CodingKeys.duration.rawValue)
    }
    
    // NSCoding解码实现
    required init?(coder: NSCoder) {
        name = coder.decodeObject(forKey: CodingKeys.name.rawValue) as? String ?? ""
        duration = coder.decodeInteger(forKey: CodingKeys.duration.rawValue)
    }
    
    // 自定义初始化方法
    init(name: String, duration: Int) {
        self.name = name
        self.duration = duration
    }
}

方案2:弃用NSKeyedArchiver,全程用Swift Codable处理

既然Exercise已经支持Codable,直接用JSONEncoder编码数组,避免依赖OC工具:

struct Workout: Codable {
    var exercises: [Exercise]
    var workoutName: String
    
    enum CodingKeys: String, CodingKey {
        case exercisesData, workoutName
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        // 用JSONEncoder直接编码Exercise数组
        let exercisesData = try JSONEncoder().encode(exercises)
        try container.encode(exercisesData, forKey: .exercisesData)
        try container.encode(workoutName, forKey: .workoutName)
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let exercisesData = try container.decode(Data.self, forKey: .exercisesData)
        exercises = try JSONDecoder().decode([Exercise].self, from: exercisesData)
        workoutName = try container.decode(String.self, forKey: .workoutName)
    }
}

二、自动合成Codable时JSONEncoder报错的原因与排查

报错核心原因

自动合成Codable要求所有属性的类型都必须遵循Codable协议,只要有一个属性不满足,就会触发格式错误。

排查步骤

  1. 检查属性类型:遍历Workout的所有属性,确认没有Any、未遵循Codable的自定义类型、OC非兼容类型(如NSMutableDictionary)。
  2. 检查类/结构体差异:如果Workout是类且继承了NSObject,自动合成Codable可能受OC属性干扰,建议改为结构体。
  3. 检查可选类型:如果有Optional类型属性为nil,JSONEncoder默认会编码为null,但如果后端不接受null值,需手动实现Codable忽略该属性。
  4. 检查嵌套类型:如果Workout包含其他自定义对象(如Trainer),必须确保这些对象也遵循Codable。

示例修复

如果Workout包含非Codable的Any类型属性,要么替换为Codable类型,要么手动忽略:

struct Workout: Codable {
    var exercises: [Exercise]
    var workoutName: String
    // 用CodingKeys忽略非Codable属性
    private var notes: Any?
    
    enum CodingKeys: String, CodingKey {
        case exercises, workoutName
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 12:24:54