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)
这是我的 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)