NSKeyedArchiver 不归档我的 Codable 类
Posted
技术标签:
【中文标题】NSKeyedArchiver 不归档我的 Codable 类【英文标题】:NSKeyedArchiver does not archive my Codable class 【发布时间】:2018-10-01 18:23:56 【问题描述】:这是我的 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:我以这种方式接收的文件路径:
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 以及其他支持的类型,但不适用于我的类型。怎么了?
【问题讨论】:
【参考方案1】:虽然@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 错误而不是崩溃。)
【讨论】:
感谢您的详细回答,一切正常。但是如何获取 NSMutableData 的 URL 或如何使用 transferFile(_:metadata:) 将保存的文件从 Apple Watch 发送到 iPhone? 您可以使用write(toFile:atomically:)
、write(toFile:options:)
、write(to:atomically:)
或write(to:options:)
方法之一将NSMutableData
写入文件。 (它从NSData
继承这些方法)。【参考方案2】:
错误信息告诉你SensorOutput
需要从NSObject派生。
但是,根本问题是您使用 NSKeyedArchiver 错误。你打电话给archiveRootObject
,就好像这种类型采用了NSCoding。它没有。它采用 Codable。如果你打算使用这种类型是 Codable 的事实,你调用 NSKeyedArchiver encodeEncodable(_:forKey:)
编码和 NSKeyedUnarchiver decodeDecodable(_:forKey:)
解码。
【讨论】:
【参考方案3】:你用错了。它采用Codable
协议而不是NSCoding
之一。 (正如@matt 指出的那样)。
你可以这样解决:
let myData = SensorOutput()
let data = try! PropertyListEncoder().encode(myData)
NSKeyedArchiver.archivedData(withRootObject: data)
【讨论】:
以上是关于NSKeyedArchiver 不归档我的 Codable 类的主要内容,如果未能解决你的问题,请参考以下文章
是否可以将带有 NSKeyedArchiver 的 NSMutableArray 保存到核心数据中?