这是我的Codable类:
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() {}
}
在这里,我尝试编写并读取该类的对象来存档:
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:我以这种方式收到的filePath:
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)
}
读取/写入适用于Int或Double以及其他受支持的类型,但不适用于我的类型。怎么了?
答案 0 :(得分:8)
尽管@ matt的答案包含解决问题的基本信息,但如果您是Swift和iOS编程的新手,可能并不明白如何应用这些信息。
您尝试使用NSKeyedArchiver.archiveRootObject(_:toFile:)
这是一种类方法,因此您无需创建NSKeyedArchiver
的实例。由于encodeEncodable(_:forKey:)
是实例方法,而不是类方法,因此您需要创建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:)
这是一种类方法,但您需要使用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错误而不是崩溃。)
答案 1 :(得分:5)
错误消息告诉您SensorOutput
需要从NSObject派生。
但是,根本问题是您使用NSKeyedArchiver时出错了。您正在呼叫archiveRootObject
,就像这种类型采用NSCoding一样。它没有。它采用Codable。如果您打算使用此类型为Codable的事实,请调用NSKeyedArchiver encodeEncodable(_:forKey:)
进行编码,并调用NSKeyedUnarchiver decodeDecodable(_:forKey:)
进行解码。
答案 2 :(得分:0)
您使用错误的方式。它采用Codable
协议而不是NSCoding
协议。 (正如@matt指出的)。
您可以这样解决:
let myData = SensorOutput()
let data = try! PropertyListEncoder().encode(myData)
NSKeyedArchiver.archivedData(withRootObject: data)