在UserDefaults中存储/检索结构的可编码字典对我不起作用

时间:2019-10-11 09:19:16

标签: xcode nsuserdefaults codable swift5

在这里迅速(v 5 / 5.1)的新手,在Codables方面遇到了困难...希望从这里的专家那里获得一些建议。

好的,我有一个来自struct的简单字典,其中的键是一个字符串。我想将字典存储在UserDefaults中(以后再检索)。这里有一些非常相似的问题,但是这些问题主要是针对嵌套结构。

第一次尝试(为简化起见,删除了错误处理):

response = HttpResponse(mimetype="application/ms-excel")
response['Content-Disposition'] = 'attachment; filename=%s' % 'example.xls'
workbook.save(response)
return response
public struct PriceStruct:Codable {
    var myPrice: Double
    var myTime: TimeInterval
    var selected: Bool
    var direction: Int
    var myHigh, myLow: Double

    enum CodingKeys: String, CodingKey {
        case myPrice = "myPrice"
        case myTime = "myTime"
        case selected = "selected"
        case direction = "direction"
        case myHigh = "myHigh"
        case myLow = "myLow"
    }
}

var myPrices: [String: PriceStruct] = [:]

// [fill myPrices with some data...]

func savePrices() {
   // error: Attempt to set a non-property-list object
   UserDefaults.standard.set(myPrices, forKey: "prices")
}

func loadPrices() {
   // obviously this doesn't work either
   let myPrices = UserDefaults.standard.data(forKey: "prices")
}

不幸的是,尝试从UserDefaults加载数据时出现错误: While I assumed from the documentation, that UserDefaults is capable of storing dictionaries, it doesn't - at least for me. Next thing I tried was using JSONEncoder like this: // this time with prior JSON encoding func savePrices() { // this works let json = try! JSONEncoder().encode(myPrices) UserDefaults.standard.set(json as Data, forKey: "prices") } func loadPrices() { // this doesn't work let json = UserDefaults.standard.data(forKey: "prices") let decoder = JSONDecoder() let decoded = try! decoder.decode(PriceStruct.self, from json!) }

我尝试过的其他变体是将编码的JSON转换为UTF8编码的字符串并存储/检索该字符串:

Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "myPrice", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"myPrice\", intValue: nil) (\"myPrice\").", underlyingError: nil))

因此,从引发的错误来看,CodingKeys似乎是问题的根源。我尝试使用NSKeyedArchiver和NSKeyedUnarchiver`进行切换,但没有成功。

我真的很想知道是否存在一种简单/通用的解决方案来在UserDefaults中保存/加载字典?

感谢您提出的所有意见和建议。谢谢!

1 个答案:

答案 0 :(得分:0)

我在我的项目中尝试了以下代码,该代码对我有用。

  

用户模型

public protocol UserModel: Codable, PrimaryKey {

    var id: String { get }
    var firstName: String? { get }
    var lastName: String? { get }
    var userName: String? { get }
    var emails: [String] { get }
}

public struct User: UserModel {

    public let id: String
    public let firstName: String?
    public let lastName: String?
    public let userName: String?
    public let emails: [String]

    public enum CodingKeys: String, CodingKey {
        case id = "Id"
        case firstName = "FirstName"
        case lastName = "LastName"
        case userName = "UserName"
        case emails = "Emails"
    }

    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        do {
            self.id = try container.decode(String.self, forKey: .id)
            self.firstName = try container.decodeIfPresent(String.self, forKey: .firstName)
            self.lastName = try container.decodeIfPresent(String.self, forKey: .lastName)
            self.userName = try container.decodeIfPresent(String.self, forKey: .userName)
            self.emails = try container.decodeIfPresent([String].self, forKey: .emails) ?? []
        }
        catch let error {
            debugPrint(error)
            throw error
        }
    }
}

我已经通过以下方式存储在userDefault中

  

用户数据类

class UserData: NSObject
{

let userDefaultKey = "user_information"

var userData: User?

    func getDictionary() -> [String: Data]
    {
        var dicInfo = [String: Data]()

        do
        {
            let _userData = try JSONEncoder().encode(userData)

            dicInfo["userData_default"]  = _userData

        }catch let error{
            print("error while save data in User Default: \(error.localizedDescription)")
        }

        return dicInfo
    }
    func saveToDefault()
    {
        let userDefault = UserDefaults.standard
        userDefault.set(getDictionary(), forKey: userDefaultKey)
        userDefault.synchronize()
    }
    func loadFromDefault()
    {
        let userDefault = UserDefaults.standard
        if let dicInfo = userDefault.object(forKey: userDefaultKey) as? [String: Data]
        {
            update(dicInfo)
        }
    }
    func update(_ dictionaryInfo: [String: Data])
    {
        do
        {
            if let _userData_data = dictionaryInfo["userData_default"]
            {
                if let _userData = try? JSONDecoder().decode(User.self, from: _userData_data) {
                    userData = _userData
                }
            }

            saveToDefault()

        }catch let error{
            print("error while load From Default data in User Default: \(error.localizedDescription)")
        }
    }
}

希望这会对您有所帮助。