我想将从CoreML预测的MLMultiArray
数据存储到本地文件中,因为Core Data
不支持这种类型,所以我试用了NSKeyedUnarchiver
,因为MLMultiArray
符合NSObject
。
但是,此对象可以是encode
并成功保存,但不能是正确的decode
。
error is: Error Domain=NSCocoaErrorDomain Code=4864 "value for key 'embedding' was of unexpected class 'MLMultiArray' (0x1e35d84b8) [/System/Library/Frameworks/CoreML.framework].
Allowed classes are:
{(
"'CoreMLApp.Embedding' (0x1002a53f8) [/private/var/containers/Bundle/Application/C86A850C-27F6-43CB-82AF-9223/CoreMLApp.app]",
"'NSArray' (0x1e3380b50) [/System/Library/Frameworks/CoreFoundation.framework]"
)}" UserInfo={NSDebugDescription=value for key 'embedding' was of unexpected class 'MLMultiArray' (0x1e35d84b8)
下面是我的对象:
class Embedding: NSObject, NSSecureCoding {
static var supportsSecureCoding: Bool = true
var id: String?
var embedding: MLMultiArray?
init(id: String, embedding: MLMultiArray) {
self.id = id
self.embedding = embedding
}
func encode(with aCoder: NSCoder) {
aCoder.encode(self.id, forKey: "id")
aCoder.encode(self.embedding, forKey: "embedding")
}
required init?(coder aDecoder: NSCoder) {
self.id = aDecoder.decodeObject(forKey: "id") as? String
self.embedding = aDecoder.decodeObject(forKey: "embedding") as? MLMultiArray
}
}
编解码部分:
private func saveEmbeddingsData(embeddings: [Embedding], fileName: String) -> Bool {
let filePath = self.getDocumentsDirectory().appendingPathComponent(fileName)
do {
let data = try NSKeyedArchiver.archivedData(withRootObject: embeddings, requiringSecureCoding: true)
try data.write(to: filePath)
return true
} catch {
print("error is: \(error.localizedDescription)")
}
return false
}
private func loadEmbeddingsData(fileName: String) -> [Embedding]? {
let filePath = self.getDocumentsDirectory().appendingPathComponent(fileName)
do {
let data = try Data(contentsOf: filePath)
let embeddings = try NSKeyedUnarchiver.unarchivedArrayOfObjects(ofClasses: [Embedding.self], from: data) as? [Embedding]
return embeddings
} catch {
print("error is: \(String(describing: error))")
}
return nil
}
private func getDocumentsDirectory() -> URL {
let arrayPaths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return arrayPaths[0]
}
我尝试使用NSCoding
而不是NSSecureCoding
,但是所有NSKeyedUnarchiver.unarchiveXXX
方法都输出错误,要求数据符合NSSecureCoding
。
1条答案
按热度按时间nr9pn0ug1#
NSSecureCoding和NSKeyedUnarchiver要求你指定你所期望的类的类型。整个想法是为了避免有人偷偷进入意想不到的、狡猾的值,这可能会危及你代码的安全性。
由于存档的是
Embedding
数组,因此存档文件还包含MLMultiArray
类型的值。这意味着在取消存档数据时,必须指定预期的NSArray
、Embedding
和MLMultiArray
类型的值。由于使用的是
NSKeyedUnarchiver.unarchivedArrayOfObjects
,因此不需要显式指定NSArray
,但需要将[Embedding.self, MLMultiArray.self]
传递给classes
参数。错误消息是一个重要提示。
这是告诉你只有
Embedding
和NSArray
是允许的,因为这是你告诉NSKeyedUnarchiver.unarchivedArrayOfObjects
所期望的,并且错误告诉你它在归档文件中找到了MLMultiArray
,但是它不在允许的类列表中。通过更改以下行可以解决此问题:
致:
对我来说,NSSecureCoding最大的问题是它破坏了封装。你的代码需要知道
Embedding
类的内部细节。一个解决方案是向Embedding
类添加helper方法来执行存档和解存档,这样其他代码就不需要知道需要指定什么类。