使用NSKeyedArchiver保存不可编码的Swift字典

问题描述 投票:-1回答:1

我正在使用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
}
swift dictionary nskeyedarchiver
1个回答
0
投票

问题是无法公开给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)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.