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

NSKeyedArchiver无法归档我的Codable类问题求助

解决NSKeyedArchiver无法归档自定义Codable类的问题

嘿,我来帮你搞定这个归档失败的问题!首先得明确核心原因:你的SensorOutput类只实现了Codable协议,但NSKeyedArchiver默认依赖的是NSCoding协议——这俩是完全独立的序列化体系,所以直接用NSKeyedArchiver处理你的类对象肯定会失败。

下面给你两种可行的解决方案,按需选择:

方案一:让类同时遵守NSCoding协议

既然要用到NSKeyedArchiver,那我们让类继承NSObject并实现NSCoding的两个核心方法,同时保留Codable(两者不冲突):

class SensorOutput: NSObject, Codable, NSCoding { 
    var timeStamp: Date? 
    var gyroX: Double? 
    var gyroY: Double? 
    var gyroZ: Double? 
    var accX: Double? 
    var accY: Double? 
    var accZ: Double? 
    var magX: Double? 
    var magY: Double? 
    var magZ: Double? 

    override init() {} 

    // 实现NSCoding的编码方法
    func encode(with coder: NSCoder) {
        coder.encode(timeStamp, forKey: "timeStamp")
        coder.encode(gyroX, forKey: "gyroX")
        coder.encode(gyroY, forKey: "gyroY")
        coder.encode(gyroZ, forKey: "gyroZ")
        coder.encode(accX, forKey: "accX")
        coder.encode(accY, forKey: "accY")
        coder.encode(accZ, forKey: "accZ")
        coder.encode(magX, forKey: "magX")
        coder.encode(magY, forKey: "magY")
        coder.encode(magZ, forKey: "magZ")
    }

    // 实现NSCoding的解码方法
    required init?(coder: NSCoder) {
        timeStamp = coder.decodeObject(forKey: "timeStamp") as? Date
        gyroX = coder.decodeObject(forKey: "gyroX") as? Double
        gyroY = coder.decodeObject(forKey: "gyroY") as? Double
        gyroZ = coder.decodeObject(forKey: "gyroZ") as? Double
        accX = coder.decodeObject(forKey: "accX") as? Double
        accY = coder.decodeObject(forKey: "accY") as? Double
        accZ = coder.decodeObject(forKey: "accZ") as? Double
        magX = coder.decodeObject(forKey: "magX") as? Double
        magY = coder.decodeObject(forKey: "magY") as? Double
        magZ = coder.decodeObject(forKey: "magZ") as? Double
    }
}

之后你就可以正常用NSKeyedArchiver归档和读取了:

// 归档示例
let myData = SensorOutput() 
myData.timeStamp = Date() 
myData.gyroX = 0.0 
myData.gyroY = 0.0 
myData.gyroZ = 0.0 
myData.accX = 0.0 
myData.accY = 0.0 
myData.accZ = 0.0 
myData.magX = 0.0
myData.magY = 0.0
myData.magZ = 0.0

// 获取文档目录路径
let documentsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let archivePath = documentsDir.appendingPathComponent("sensor_data.archive")

// 执行归档
do {
    let archiveData = try NSKeyedArchiver.archivedData(withRootObject: myData, requiringSecureCoding: false)
    try archiveData.write(to: archivePath)
    print("归档成功!")
} catch {
    print("归档失败:\(error.localizedDescription)")
}

// 读取示例
do {
    let savedData = try Data(contentsOf: archivePath)
    if let decodedSensorData = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(savedData) as? SensorOutput {
        print("读取成功,时间戳:\(decodedSensorData.timeStamp ?? Date())")
    }
} catch {
    print("读取失败:\(error.localizedDescription)")
}

方案二:用Codable原生的编码器替代NSKeyedArchiver

如果不想折腾NSCoding,可以直接用Codable自带的PropertyListEncoder(生成的格式和NSKeyedArchiver类似),完全不需要修改原类:

// 归档示例
let encoder = PropertyListEncoder()
encoder.outputFormat = .binary // 可选,和NSKeyedArchiver的二进制格式一致

do {
    let encodedData = try encoder.encode(myData)
    try encodedData.write(to: archivePath)
    print("归档成功!")
} catch {
    print("归档失败:\(error.localizedDescription)")
}

// 读取示例
let decoder = PropertyListDecoder()
do {
    let savedData = try Data(contentsOf: archivePath)
    let decodedSensorData = try decoder.decode(SensorOutput.self, from: savedData)
    print("读取成功,时间戳:\(decodedSensorData.timeStamp ?? Date())")
} catch {
    print("读取失败:\(error.localizedDescription)")
}

这个方案更简洁,因为你本来就实现了Codable,直接用原生的编码器解码器就好,不需要额外实现NSCoding的方法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:38:02