これが私の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)
}
これにより、アーカイブの処理中にエラーが発生します: エラーのスクリーンショット
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、およびサポートされている他のタイプで機能しますが、私のタイプでは機能しません。どうしましたか?
@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)")
}
_
(アーカイブが破損している場合にクラッシュする代わりにSwiftエラー)をスローするため、decodeTopLevelDecodable
ではなくdecodeDecodable
メソッドを使用します。)
エラーメッセージは、SensorOutput
がNSObjectから派生する必要があることを示しています。
ただし、根本的な問題は、NSKeyedArchiverを間違って使用していることです。このタイプがNSCodingを採用したかのように動作して、archiveRootObject
を呼び出しています。そうではありません。 Codableを採用しています。このタイプがCodableであるという事実を使用する場合は、NSKeyedArchiver encodeEncodable(_:forKey:)
を呼び出してエンコードし、NSKeyedUnarchiver decodeDecodable(_:forKey:)
を呼び出してデコードします。
あなたはそれを間違った方法で使っていました。 Codable
プロトコルではなくNSCoding
プロトコルを採用しています。 (@ mattが指摘したように)。
あなたはそれをそのように解決することができます:
let myData = SensorOutput()
let data = try! PropertyListEncoder().encode(myData)
NSKeyedArchiver.archivedData(withRootObject: data)