在 UserDefaults 中存储自定义对象数组

2023-11-30

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

这是我的代码:

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://"))
            }
        }
    }
}

它给了我这些错误:

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

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

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


如果您确实想使用 UserDefaults 保存数据,最简单的方法是使用一个类并使其符合 NSCoding。关于您的全局 var domainSchemas,我建议使用单例或扩展 UserDefaults 并为其创建一个计算属性:


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"}]


如果您更喜欢使用 Codable 方法来使用 UserDefaults 保存数据:


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"}]

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

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"}]
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 UserDefaults 中存储自定义对象数组 的相关文章

随机推荐

  • 在实体框架中使用带有输入参数的 ObjectResult 存储过程的正确方法是什么? (输出映射到复杂类型属性)

    我有几个列表框 它们有一个 SelectedItem 属性 我打算将其用作输入参数来执行实体框架中的存储过程 我现在意识到 作为存储过程的结果 轻松返回实体对象的唯一希望是将存储过程 或函数导入 映射到与输出匹配的复杂类型 使用朱莉勒曼的帖
  • 共享模块中未使用的组件是否会减慢我的应用程序的速度?

    在我的电子组件中 我导入了我的共享模块 具有特色品牌 组件 产品列表 组件等 并且还导入了其他类别 视频游戏 玩具等 中的共享模块 我的shared modules中的一些组件在导入时没有被使用 我的共享模块中这些未使用的组件会减慢我的应用
  • 在 WPF 中生成和绘制视频的快速方法是什么?

    我正在编写一个视频播放器来播放我们的 ASIC 捕获的帧 它们采用自定义格式 并且为我提供了解码 ASIC 状态的功能 视频可以是从 640x480 到 2560x1200 的任何尺寸 每个状态周期的输出是 16x16 像素块 我必须将其显
  • R.java android studio 中 GradientColor_fontVariationSettings 的重复实例

    我现在已经在 android studio 中进行了相当多的编码 最近出现了一个问题 项目无法编译 我将错误追溯到重复的变量 public static final int GradientColor fontVariationSettin
  • Android JavaMail 应用程序 - CertPathValidatorException:未找到证书路径的信任锚

    请在复制之前阅读我的问题 我在使用自签名证书时阅读了许多有关此错误的问题和答案 但是 我的问题是在尝试连接到 GMAIL imap 服务器时收到此错误 所以 我真的需要一些帮助 我的代码是 private String ReadMailbo
  • 我必须在 python 源代码中嵌入代码版本有什么实际原因吗?

    我必须在源代码中嵌入代码版本有什么实际原因吗 我明确地感兴趣setup py但也有一些用处 version 我所说的 嵌入源代码 是指我必须将版本号以文本形式写入文件中 而不是通过其他方式填充 python 字段 在其他语言中 我将构建脚本
  • 使用 C# 删除 jpeg 图像的 EXIF 数据中除两个字段以外的所有字段

    我正在使用 C 和 ImageFactory 库 来自 ImageProcessor org 来大幅修改 jpg 图像 它可以进行拉直 裁剪 阴影细节增强等 它正在完全工作并成功地将新图像写入文件 但该文件包含原始 EXIF 数据 其中大部
  • APNS - 通知推送 ios:由对等 PHP 重置连接

    我的推送通知工作正常 但有时 它会从无处开始给出错误 Stream socket client SSL 连接被对等方重置 奇怪的是我不需要做任何事情来解决它 只需等待 一段时间后 它又开始恢复工作 我知道这是一个复制许多问题 例如 通知推送
  • 使用类名作为 JSON Jackson 序列化的根键

    假设我有一个 pojo import org codehaus jackson map public class MyPojo int id public int getId return this id public void setId
  • template 模板类,如果存在则调用函数

    我有一个带有模板模板参数的简单函数 它的意思是采用STL容器 将智能ptr转换为普通ptr 这是一个C 03项目 但我也对C 11的答案感兴趣 template
  • 在 MATLAB 中查找总和为特定数字的向量元素

    让我们考虑有一个向量VEC 有没有办法找到哪些向量元素可以分组 以便 MATLAB 中它们的总和为给定数字 NUM 例如如果VEC 2 5 7 10 and NUM 17 所请求的算法应提供子向量的答案 2 5 10 and 7 10 总结
  • 使用 C# 自动运行应用程序 [关闭]

    很难说出这里问的是什么 这个问题模棱两可 含糊不清 不完整 过于宽泛或言辞激烈 无法以目前的形式合理回答 如需帮助澄清此问题以便重新打开 访问帮助中心 我想创建一个在启动机器后自动运行的应用程序 任何人都可以帮助我如何在 C 上做到这一点
  • 为什么不能使用正则表达式来解析 HTML/XML:通俗易懂的正式解释

    SO 上的每一天都会询问有关使用正则表达式解析 X HTML 或 XML 的问题 虽然它相对容易想出演示正则表达式对于此任务不可行的示例或与表达式集合为了代表这个概念 我仍然找不到formal解释为什么这不可能用外行人的话来完成 到目前为止
  • 如何重新创建已删除的目标?

    我已经删除了我的应用程序目标 现在我所有的构建选项都消失了 我无法运行我的项目 因为我缺少目标 我怎样才能重新生成它 你有两个选择 第一个是 DarkDust 的建议 从备份或 SCM 存储库 如果有的话 进行恢复 如果你两者都没有 你必须
  • jQuery UI 日期选择器添加天数

    我正在尝试创建一些范围系统来在酒店网站上预订房间 并且我正在使用 jQuery UI Datepicker 来允许用户选择他们的入住日期 然后我想做的是创建另一个简单的 过夜数 字段 并让 jQuery Datepicker 获取入住日期
  • GraalVM 本机映像无法处理日志

    我尝试做的事情 mvn package Dpackaging docker native Dmicronaut runtime lambda Pgraalvm 我得到什么 Caused by com oracle graal pointst
  • 如何使用Python通过空格键开始移动乌龟

    我正在尝试在 python 中设置一个简单的乌龟程序 在其中我可以通过按空格键开始移动乌龟 并且他会一直移动 直到我再次按下空格键 我可以用空格键让他移动固定距离 但无法让它继续 这是我正在处理的内容 from turtle import
  • 在VBA中使用Solver将计算模式设置为手动

    在试图帮助解决这个问题 我在 VBA 中的 Solver 中遇到了一些非常奇怪的行为 我想知道如果其他人可以复制它或者如果我的系统有问题 Windows 10 Excel 2016 以及如果有人能告诉我发生了什么事 工作簿设置非常简单 这是
  • 隐藏 ICS 返回主页任务切换器按钮

    只是想知道如何以编程方式隐藏 ICS 返回 主页 等软件按钮 就像 Youtube 应用程序在播放视频时所做的那样 我想在视频播放时隐藏它们 但如果用户点击屏幕则将它们显示出来 我似乎无法在网络上或谷歌文档中找到它 Pinxue 正好 你想
  • 在 UserDefaults 中存储自定义对象数组

    我花了很长时间试图弄清楚如何在 UserDefaults 中存储我的自定义结构数组 这是我的代码 struct DomainSchema Codable var domain String var schema String var dom