Ответ 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) }
person
Jake
schedule
15.04.2019
Patient
? - person denis_lor   schedule 15.04.2019do { try ...} catch {print(error)}
, тогда вы увидите, что происходит не так - person Johnykutty   schedule 15.04.2019let encodeData = try! JSONEncoder().encode(patientList)
если я делаю это так, я получаю эту ошибку: общий параметр «T» не может быть выведен - person fynn metzler   schedule 15.04.2019