Vadian 的回答是正确的,您不能将 NSKeyedArchiver 与结构一起使用。让您的所有对象都符合Codable
是重现您正在寻找的行为的最佳方式。我做 Vadian 做的事情,但我也可以使用协议扩展来使其更安全。
import UIKit
struct Patient: Codable {
var name: String
var number: String
var resultArray: [Diagnose]
var diagnoseArray: [Diagnose]
}
struct Diagnose: Codable {
var name: String
var treatments: [Treatment]
var isPositiv : Bool
var isExtended : Bool
}
struct Treatment: Codable {
var name: String
var wasMade : Bool
}
let newPatient = Patient(name: "John Doe",
number: "123",
resultArray: [Diagnose(name: "Result", treatments: [Treatment(name: "Treat1", wasMade: false)], isPositiv: false, isExtended: false)],
diagnoseArray: [Diagnose(name: "Diagnose", treatments: [Treatment(name: "Treat2", wasMade: false)], isPositiv: false, isExtended: false)])
let patientList: [Patient] = [newPatient]
引入一个协议来管理对象的编码和保存。
这不必继承自,Codable
但为了简单起见,它适用于本示例。
/// Objects conforming to `CanSaveToDisk` have a save method and provide keys for saving individual objects or a list of objects.
protocol CanSaveToDisk: Codable {
/// Provide default logic for encoding this value.
static var defaultEncoder: JSONEncoder { get }
/// This key is used to save the individual object to disk. This works best by using a unique identifier.
var storageKeyForObject: String { get }
/// This key is used to save a list of these objects to disk. Any array of items conforming to `CanSaveToDisk` has the option to save as well.
static var storageKeyForListofObjects: String { get }
/// Persists the object to disk.
///
/// - Throws: useful to throw an error from an encoder or a custom error if you use stage different from user defaults like the keychain
func save() throws
}
使用协议扩展,我们添加了一个选项来保存这些对象的数组。
extension Array where Element: CanSaveToDisk {
func dataValue() throws -> Data {
return try Element.defaultEncoder.encode(self)
}
func save() throws {
let storage = UserDefaults.standard
storage.set(try dataValue(), forKey: Element.storageKeyForListofObjects)
}
}
我们扩展了耐心对象,这样它就可以知道保存时要做什么。
我使用“存储”,以便可以与 NSKeychain 交换。如果您要保存敏感数据(如患者信息),您应该使用钥匙串而不是 UserDefaults。此外,请确保您在提供应用程序的任何市场中都遵守健康数据的安全和隐私最佳做法。国家之间的法律可能会有非常不同的体验。UserDefaults 可能不够安全。
有很多很棒的钥匙串包装器可以让事情变得更容易。UserDefaults 只是使用键设置数据。钥匙串也是如此。像https://github.com/evgenyneu/keychain-swift这样的包装器的行为类似于我在下面使用 UserDefaults 的方式。为了完整性,我已经注释掉了等效使用的样子。
extension Patient: CanSaveToDisk {
static var defaultEncoder: JSONEncoder {
let encoder = JSONEncoder()
// add additional customization here
// like dates or data handling
return encoder
}
var storageKeyForObject: String {
// "com.myapp.patient.123"
return "com.myapp.patient.\(number)"
}
static var storageKeyForListofObjects: String {
return "com.myapp.patientList"
}
func save() throws {
// you could also save to the keychain easily
//let keychain = KeychainSwift()
//keychain.set(dataObject, forKey: storageKeyForObject)
let data = try Patient.defaultEncoder.encode(self)
let storage = UserDefaults.standard
storage.setValue(data, forKey: storageKeyForObject)
}
}
保存已简化,请查看下面的 2 个示例!
do {
// saving just one patient record
// this saves this patient to the storageKeyForObject
try patientList.first?.save()
// saving the entire list
try patientList.save()
} catch { print(error) }