在 UserDefaults 中存储自定义对象数组 [英] Storing array of custom objects in UserDefaults

查看:34
本文介绍了在 UserDefaults 中存储自定义对象数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我花了很长时间试图弄清楚如何在 UserDefaults 中存储我的自定义结构数组.

这是我的代码:

struct DomainSchema: Codable {var 域:字符串var 架构:字符串}var domainSchemas: [DomainSchema] {得到 {如果 UserDefaults.standard.object(forKey: "domainSchemas") != nil {让 data = UserDefaults.standard.value(forKey: "domainSchemas") as!数据让 domainSchema = 试试?PropertyListDecoder().decode(DomainSchema.self, from: data)返回域架构!}返回零}放 {UserDefaults.standard.set(try? PropertyListEncoder().encode(newValue), forKey: "domainSchemas")}}结构设置视图:查看{var主体:一些视图{虚拟堆栈{ForEach(domainSchemas, id: \.domain) { domainSchema in堆栈{文本(域Schema.domain)文本(domainSchema.schema)}}//清除历史按钮}.onAppear {如果(域Schemas.isEmpty){domainSchemas.append(DomainSchema(域:reddit.com",架构:apollo://"))}}}}

它给了我这些错误:

<块引用>

无法将类型为DomainSchema"的返回表达式转换为返回类型[DomainSchema]"

<块引用>

'nil' 与返回类型 '[DomainSchema]' 不兼容

我不太确定如何获取对象数组而不是单个对象,或者如何解决 nil 不兼容错误...

解决方案

如果你真的想使用 UserDefaults 持久化你的数据,最简单的方法是使用一个类并使其符合 NSCoding.关于您的全局 var domainSchemas,我建议使用单例或扩展 UserDefaults 并为它创建一个计算属性:


class DomainSchema: NSObject, NSCoding {var 域:字符串var 架构:字符串初始化(域:字符串,架构:字符串){self.domain = 域self.schema = 模式}所需的初始化(编码器解码器:NSCoder){self.domain =decoder.decodeObject(forKey: "domain") as?细绳 ??"self.schema =decoder.decodeObject(forKey: "schema") as?细绳 ??"}func 编码(带编码器:NSCoder){coder.encode(域,forKey:域")coder.encode(schema, forKey: schema")}}


extension UserDefaults {var domainSchemas: [DomainSchema] {得到 {guard let data = UserDefaults.standard.data(forKey: "domainSchemas") else { return [] }return (try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data)) as?[域架构] ??[]}放 {UserDefaults.standard.set(try? NSKeyedArchiver.archivedData(withRootObject: newValue, requiresSecureCoding: false), forKey: "domainSchemas")}}}


用法:

UserDefaults.standard.domainSchemas = [.init(domain: "a", schema: "b"), .init(domain: "c", schema: "d")]UserDefaults.standard.domainSchemas//[{NSObject, 域a",架构b"},{NSObject,域c",架构d"}]



如果您更喜欢使用 UserDefaults 持久化数据的 Codable 方法:


struct DomainSchema: Codable {var 域:字符串var 架构:字符串初始化(域:字符串,架构:字符串){self.domain = 域self.schema = 模式}}


extension UserDefaults {var domainSchemas: [DomainSchema] {得到 {guard let data = UserDefaults.standard.data(forKey: "domainSchemas") else { return [] }return (try? PropertyListDecoder().decode([DomainSchema].self, from: data)) ??[]}放 {UserDefaults.standard.set(try? PropertyListEncoder().encode(newValue), forKey: "domainSchemas")}}}


用法:

UserDefaults.standard.domainSchemas = [.init(domain: "a", schema: "b"), .init(domain: "c", schema: "d")]UserDefaults.standard.domainSchemas//[{域a",架构b"},{域c",架构d"}]


我认为最好的选择是不使用 UserDefaults,创建一个单例共享实例",在那里声明一个 domainSchemas 属性并将您的 json 数据保存在您的应用程序支持目录的子目录中:

扩展 URL {静态 var domainSchemas: URL {让 applicationSupport = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).首先!让 bundleID = Bundle.main.bundleIdentifier ??公司名称"让 subDirectory = applicationSupport.appendingPathComponent(bundleID, isDirectory: true)尝试?FileManager.default.createDirectory(at: subDirectory, withIntermediateDirectories: true, attributes: nil)return subDirectory.appendingPathComponent("domainSchemas.json")}}


class 共享 {静态 let 实例 = Shared()私人初始化(){}var domainSchemas: [DomainSchema] {得到 {守卫让数据=尝试?数据(contentsOf: .domainSchemas) else { return [] }返回(试试?JSONDecoder().decode([DomainSchema].self, from: data)) ??[]}放 {尝试?JSONEncoder().encode(newValue).write(to: .domainSchemas)}}}


用法:

Shared.instance.domainSchemas = [.init(domain: "a", schema: "b"), .init(domain: "c", schema: "d")]Shared.instance.domainSchemas//[{域a",架构b"},{域c",架构d"}]

I'm having a heck of a time trying to figure out how to store an array of my custom struct in UserDefaults.

Here is my code:

struct DomainSchema: Codable {
    var domain: String
    var schema: String
}

var domainSchemas: [DomainSchema] {
    get {
        if UserDefaults.standard.object(forKey: "domainSchemas") != nil {
            let data = UserDefaults.standard.value(forKey: "domainSchemas") as! Data
            let domainSchema = try? PropertyListDecoder().decode(DomainSchema.self, from: data)
            
            return domainSchema!
        }
        
        return nil
    }
    
    set {
        UserDefaults.standard.set(try? PropertyListEncoder().encode(newValue), forKey: "domainSchemas")
    }
}

struct SettingsView: View {
    var body: some View {
        VStack {
            ForEach(domainSchemas, id: \.domain) { domainSchema in
                HStack {
                    Text(domainSchema.domain)
                    Text(domainSchema.schema)
                }
            }
            
            // clear history button
        }
        .onAppear {
            if (domainSchemas.isEmpty) {
                domainSchemas.append(DomainSchema(domain: "reddit.com", schema: "apollo://"))
            }
        }
    }
}

It is giving me these errors:

Cannot convert return expression of type 'DomainSchema' to return type '[DomainSchema]'

'nil' is incompatible with return type '[DomainSchema]'

I'm not really sure how to get an array of the objects instead of just a single object, or how to resolve the nil incompatibility error...

解决方案

If you really want to persist your data using UserDefaults the easiest way would be to use a class and conform it to NSCoding. Regarding your global var domainSchemas I would recommend using a singleton or extend UserDefaults and create a computed property for it there:


class DomainSchema: NSObject, NSCoding {
    var domain: String
    var schema: String
    init(domain: String, schema: String) {
        self.domain = domain
        self.schema = schema
    }
    required init(coder decoder: NSCoder) {
        self.domain = decoder.decodeObject(forKey: "domain") as? String ?? ""
        self.schema = decoder.decodeObject(forKey: "schema") as? String ?? ""
    }
    func encode(with coder: NSCoder) {
        coder.encode(domain, forKey: "domain")
        coder.encode(schema, forKey: "schema")
    }
}


extension UserDefaults {
    var domainSchemas: [DomainSchema] {
        get {
            guard let data = UserDefaults.standard.data(forKey: "domainSchemas") else { return [] }
            return (try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data)) as? [DomainSchema] ?? []
        }
        set {
            UserDefaults.standard.set(try? NSKeyedArchiver.archivedData(withRootObject: newValue, requiringSecureCoding: false), forKey: "domainSchemas")
        }
    }
}


Usage:

UserDefaults.standard.domainSchemas = [.init(domain: "a", schema: "b"), .init(domain: "c", schema: "d")]

UserDefaults.standard.domainSchemas  // [{NSObject, domain "a", schema "b"}, {NSObject, domain "c", schema "d"}]



If you prefer the Codable approach persisting the Data using UserDefaults as well:


struct DomainSchema: Codable {
    var domain: String
    var schema: String
    init(domain: String, schema: String) {
        self.domain = domain
        self.schema = schema
    }
}


extension UserDefaults {
    var domainSchemas: [DomainSchema] {
        get {
            guard let data = UserDefaults.standard.data(forKey: "domainSchemas") else { return [] }
            return (try? PropertyListDecoder().decode([DomainSchema].self, from: data)) ?? []
        }
        set {
            UserDefaults.standard.set(try? PropertyListEncoder().encode(newValue), forKey: "domainSchemas")
        }
    }
}


Usage:

UserDefaults.standard.domainSchemas = [.init(domain: "a", schema: "b"), .init(domain: "c", schema: "d")]

UserDefaults.standard.domainSchemas  // [{domain "a", schema "b"}, {domain "c", schema "d"}]


I think the best option would be to do not use UserDefaults, create a singleton "shared instance", declare a domainSchemas property there and save your json Data inside a subdirectory of you application support directory:

extension URL {
    static var domainSchemas: URL {
        let applicationSupport = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!
        let bundleID = Bundle.main.bundleIdentifier ?? "company name"
        let subDirectory = applicationSupport.appendingPathComponent(bundleID, isDirectory: true)
        try? FileManager.default.createDirectory(at: subDirectory, withIntermediateDirectories: true, attributes: nil)
        return subDirectory.appendingPathComponent("domainSchemas.json")
    }
}


class Shared {
    static let instance = Shared()
    private init() { }
    var domainSchemas: [DomainSchema] {
        get {
            guard let data = try? Data(contentsOf: .domainSchemas) else { return [] }
            return (try? JSONDecoder().decode([DomainSchema].self, from: data)) ?? []
        }
        set {
            try? JSONEncoder().encode(newValue).write(to: .domainSchemas)
        }
    }
}


Usage:

Shared.instance.domainSchemas = [.init(domain: "a", schema: "b"), .init(domain: "c", schema: "d")]

Shared.instance.domainSchemas  // [{domain "a", schema "b"}, {domain "c", schema "d"}]

这篇关于在 UserDefaults 中存储自定义对象数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆