NSKeyedArchiver 不存档我的 Codable class

NSKeyedArchiver does not archive my Codable class

这是我的 Codable class:

class SensorOutput: Codable {

    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?

    init() {}
}

这里我尝试写入和读取那个class的对象到文件:

    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

    NSKeyedArchiver.archiveRootObject(myData, toFile: filePath)

    if let Data = NSKeyedUnarchiver.unarchiveObject(withFile: filePath) as? SensorOutput {
        print (Data)
    }

归档过程中报错: Error screenshot

PS: 我这样接收的文件路径:

var filePath: String {
    //1 - manager lets you examine contents of a files and folders in your app; creates a directory to where we are saving it
    let manager = FileManager.default
    //2 - this returns an array of urls from our documentDirectory and we take the first path
    let url = manager.urls(for: .documentDirectory, in: .userDomainMask).first
    print("this is the url path in the documentDirectory \(String(describing: url))")
    //3 - creates a new path component and creates a new file called "Data" which is where we will store our Data array.
    return (url!.appendingPathComponent("Data").path)
}

Reading/writing 适用于 Int 或 Double 以及其他支持的类型,但不适用于我的类型。怎么了?

错误消息告诉您 SensorOutput 需要从 NSObject 派生。

但是,问题的根源是你使用的NSKeyedArchiver不对。您正在调用 archiveRootObject,就像此类型采用了 NSCoding 一样。它没有。它采用 Codable。如果你打算使用这个类型是 Codable 的事实,你调用 NSKeyedArchiver encodeEncodable(_:forKey:) 编码和 NSKeyedUnarchiver decodeDecodable(_:forKey:) 解码。

尽管@matt 的回答包含解决您问题的基本信息,但如果您是 Swift 和 iOS 编程新手,可能不太清楚如何应用这些信息。

您尝试使用 NSKeyedArchiver.archiveRootObject(_:toFile:),这是一种 class 方法,因此您不必创建 NSKeyedArchiver 的实例。由于 encodeEncodable(_:forKey:) 是实例方法,而不是 class 方法,因此您需要创建 NSKeyedArchiver 的实例才能使用它。您还需要为归档程序创建一个 NSMutableData 以附加字节,并且您必须在编码对象后调用 finishEncoding

    let sensorOutput = SensorOutput()
    sensorOutput.timeStamp = Date()

    let mutableData = NSMutableData()
    let archiver = NSKeyedArchiver(forWritingWith: mutableData)
    try! archiver.encodeEncodable(sensorOutput, forKey: NSKeyedArchiveRootObjectKey)
    archiver.finishEncoding()

    // You can now write mutableData to a file or send it to your server
    // or whatever.

同样,您尝试使用 NSKeyedUnarchiver.unarchiveObject(withFile:),这是一个 class 方法,但您需要使用 decodeDecodable(_:forKey:)decodeTopLevelDecodable(_:forKey:),它们是实例方法。所以你需要读取存档数据并使用它来创建 NSKeyedUnarchiver.

的实例
// Read in the data from a file or your server or whatever.
// I'll just make an immutable copy of the archived data for this example.
let data = mutableData.copy() as! Data

let unarchiver = NSKeyedUnarchiver(forReadingWith: data)
do {
    if let sensorOutputCopy = try unarchiver.decodeTopLevelDecodable(SensorOutput.self, forKey: NSKeyedArchiveRootObjectKey) {
        print("deserialized sensor output: \(sensorOutputCopy)")
    }
} catch {
    print("unarchiving failure: \(error)")
}

(我更喜欢 decodeTopLevelDecodable 方法而不是 decodeDecodable,因为如果存档损坏,它会抛出 Swift 错误而不是崩溃。)

你用错了。它采用 Codable 协议而不是 NSCoding 协议。 (正如@matt 指出的).

你可以这样解决:

let myData = SensorOutput()
let data = try! PropertyListEncoder().encode(myData)
NSKeyedArchiver.archivedData(withRootObject: data)