我正在使用NSKeyedArchiver保存一个包含字典的快速结构。我使用NSKeyedArchiver的原因是因为字典具有与其关联的非编码变量。我从Paul Hudson开始遵循此指南。
我遇到的问题是,我不断收到错误消息“由于格式不正确,无法写入数据。”在“让已编码=尝试使用encoder.encode(test)“这似乎适用于非编码类型,但不适用于dictovnay类型。有人知道使该编码起作用的方法吗?这是代码:
import SwiftUI
import Combine
import HealthKit
struct Testing: View {
func saveData(){
let test = TestHealthSample(
myHKUnit : [Unit.imperial : HKUnit.kilocalorie(), Unit.metric : HKUnit.kilocalorie()],
isFavorite: true
)
let encoder = JSONEncoder()
do {
let encoded = try encoder.encode(test)
let str = String(decoding: encoded, as: UTF8.self)
print(str)
} catch {
print(error.localizedDescription)
}
}
var body: some View {
Text("Test")
.onAppear{
self.saveData()
}
}
}
struct TestHealthSample{
var myHKUnit : [Unit: HKUnit]
var isFavorite : Bool
}
extension TestHealthSample: Codable {
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: TestCodingKeys.self)
isFavorite = try container.decode(Bool.self, forKey: .isFavorite)
let hkUnitData = try container.decode(Data.self, forKey: .myHKUnit)
myHKUnit = try (NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(hkUnitData) as? [Unit:HKUnit]) ?? [Unit.metric : HKUnit.count()]
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: TestCodingKeys.self)
try container.encode(isFavorite, forKey: .isFavorite)
let hkUnitData = try NSKeyedArchiver.archivedData(withRootObject: myHKUnit, requiringSecureCoding: false)
try container.encode(hkUnitData, forKey: .myHKUnit)
}
}
enum TestCodingKeys: String, CodingKey {
case myHKUnit
case isFavorite
}
enum Unit : String, Codable{
case metric
case imperial
}
问题是无法公开给Objective-C的Unit
枚举。
您必须添加逻辑以将枚举映射到其原始值,反之亦然,类似这样
extension TestHealthSample: Codable {
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: TestCodingKeys.self)
isFavorite = try container.decode(Bool.self, forKey: .isFavorite)
let hkUnitData = try container.decode(Data.self, forKey: .myHKUnit)
let myHKUnitObjC = try (NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(hkUnitData) as? [String: HKUnit]) ?? [Unit.metric.rawValue : HKUnit.count()]
var myHKUnitData = [Unit:HKUnit]()
for (key, value) in myHKUnitObjC {
myHKUnitData[Unit(rawValue: key)!] = value
}
myHKUnit = myHKUnitData
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: TestCodingKeys.self)
try container.encode(isFavorite, forKey: .isFavorite)
var myHKUnitObjc = [String:HKUnit]()
for (key, value) in myHKUnit {
myHKUnitObjc[key.rawValue] = value
}
let hkUnitData = try NSKeyedArchiver.archivedData(withRootObject: myHKUnitObjc, requiringSecureCoding: false)
try container.encode(hkUnitData, forKey: .myHKUnit)
}
}