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
相关产品推荐
相关产品推荐

