如何在 SwiftUI 中配置 SwiftData

news2024/12/23 19:04:09

在这里插入图片描述

文章目录

    • 前言
    • 创建模型
    • 模式和版本控制
    • 迈出关键的一步
    • 创建迁移计划
    • 创建模型容器
    • 从视图中查询模型
    • 从视图中访问模型上下文
    • 总结

前言

在 WWDC 2023 上,Apple 宣布了一个备受期待的新持久性刷新,以一种新的框架形式出现:SwiftData。SwiftData 从 iOS 17 开始提供,允许使用 Swift 类型对应用程序的持久性数据进行建模,并以类型安全和声明性的方式执行 CRUD 操作。

在本文中,将展示如何配置 SwiftData 用于一个 SwiftUI 应用程序,并分享在这个过程中学到的一些经验。

创建模型

假设想要制作一个应用程序,允许用户保存他们访问的餐馆,并希望使用 SwiftData 在设备上持久保存这些信息。

首先,需要创建一个模型来表示餐馆的访问,通过使用 SwiftData 的 Model 宏对 Swift 类进行修饰:

DiaryEntry.swift

import SwiftData

@Model
final class DiaryEntry {
    let restaurant: String
    let createdAt: Date

    init(restaurant: String, createdAt: Date = .now) {
        self.restaurant = restaurant
        self.createdAt = createdAt
    }
}

该模型定义了两个属性:restaurant 表示用户访问的餐馆名称,createdAt 表示访问餐馆的日期。

正如所看到的,将现有模型转换为 SwiftData 模型非常简单,通常只需要使用 @Model 宏进行修饰即可。

模式和版本控制

如在 “使用 SwiftData 模式定义的模式” WWDC 会议中展示的那样,将每个应用程序模型的每个版本封装在其模式类型中是一个很好的实践。这是实现在不同版本的 SwiftData 模型之间无缝切换的第一步。

要创建一个模式版本,定义一个符合 VersionedSchema 协议的新类型,并通过实现 versionIdentifiermodels 属性来进行确认:

DiaryEntrySchemaV1.swift

import SwiftData

enum DiaryEntryV1Schema: VersionedSchema {
    static var versionIdentifier: String? = "v1"
    static var models: [AnyPersistentModel.Type] { [DiaryEntry.self] }

    @Model
    final class DiaryEntry {
        let restaurant: String
        let createdAt: Date

        init(restaurant: String, createdAt: Date = .now) {
            self.restaurant = restaurant
            self.createdAt = createdAt
        }
    }
}

可以将 versionIdentifier 属性设置为任何唯一标识模式版本的字符串。还需要将 models 属性设置为包含此模式版本的所有 SwiftData 模型的数组,包括所有关系类型。

迈出关键的一步

现在,模型已经命名空间化到模式类型中,需要在整个应用程序中使用模型类型的完全限定名称(DiaryEntryV1Schema.DiaryEntry)。

这样做的问题是,如果需要创建模式的新版本,将需要遍历整个代码库并更新对模型类型的所有引用,以使用新版本的模式。

为了防止这种情况发生,可以创建一个名为 DiaryEntry 的类型别名,引用当前模型的版本,并在整个应用程序中使用这个新的类型别名:

DiaryEntry.swift

typealias DiaryEntry = DiaryEntryV1Schema.DiaryEntry

当需要更改模式的版本时,只需更新类型别名,而无需遍历整个代码库并更新对模型类型的所有引用。

创建迁移计划

下一步是创建一个迁移计划,告诉 SwiftData 如何从一个模式版本转换数据到另一个版本。

通过创建符合 SchemaMigrationPlan 协议的新类型来定义 SwiftData 的迁移计划:

DiaryEntryMigrationPlan.swift

import SwiftData

enum MigrationPlan: SchemaMigrationPlan {
    static var schemas: [VersionedSchema.Type] {
        [
            DiaryEntryV1Schema.self
        ]
    }

    static var stages: [MigrationStage] {
        []
    }
}

如上所示,上述迁移计划定义了一个名为 DiaryEntryV1Schema 的模式,并且没有迁移阶段。由于应用程序只有一个模式版本,因此目前不需要定义任何迁移阶段。

即使目前不需要迁移任何数据,也要提前进行所有这些设置,这样当需要时,所有配置都已准备就绪。

创建模型容器

一旦定义了模型和模式,需要创建一个模型容器,并通过 SwiftData 的 modelContainer 视图修饰符将其提供给应用程序的视图层次结构:

FoodieDiariesApp.swift

import SwiftUI
import SwiftData

@main
struct FoodieDiariesApp: App {
    let container: ModelContainer

    init() {
        do {
            container = try ModelContainer(
                for: [DiaryEntry.self],
                migrationPlan: MigrationPlan.self,
                ModelConfiguration(for: [DiaryEntry.self])
            )
        } catch {
            fatalError("无法初始化容器...")
        }
    }

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .modelContainer(container)
    }
}

与 “使用 SwiftData 模式定义的模式” WWDC 会议中显示的设置代码不同,如果要使用迁移计划,需要使用三个参数来初始化模型容器:

  1. 应用程序使用的 SwiftData 模型类型。
  2. 之前创建的迁移计划的类型。
  3. 用于要使用的已标记为 @Model 的类型的 ModelConfiguration 实例。尽管最后一个参数看起来多余,但不传递它将导致运行时崩溃。

为了简化操作,建议创建一个第二个类型别名,用于封装当前模式类型(然后可以使用它来初始化模型容器),并修改之前创建的 DiaryEntry 类型别名以使用模式类型:

DiaryEntry.swift

typealias DiarySchema = DiaryEntryV1Schema
typealias DiaryEntry = DiarySchema.DiaryEntry

当需要更改模式的版本时,只需更新类型别名,而无需遍历整个代码库并更新对模型类型的所有引用。

从视图中查询模型

modelContainer 视图修饰符通过 SwiftUI 的环境将模型容器提供给所有子视图。SwiftData 附带了一个 @Query 属性包装器,它使用环境中的模型容器直接从视图中查询模型:

DiaryEntryListView.swift

import SwiftUI
import SwiftData

struct DiaryEntryListView: View {
    @Query(sort: \.createdAt, order: .reverse) private var entries: [DiaryEntry]

    var body: some View {
        List {
            ForEach(entries) { entry in
                Text(entry.restaurant)
            }
        }
    }
}

上述的 @Query 属性包装器还允许通过键路径以一种简洁和类型安全的方式对结果进行排序和过滤 。

从视图中访问模型上下文

由于环境中提供了模型容器,因此还可以直接从视图中访问模型上下文,以执行诸如从数据库中删除条目之类的操作:

DiaryEntryListView.swift

import SwiftUI
import SwiftData

struct DiaryEntryListView: View {
    @Environment(\.modelContext) private var modelContext
    @Query(sort: \.createdAt, order: .reverse) private var entries: [DiaryEntry]

    var body: some View {
        List {
            ForEach(entries) { entry in
                Text(entry.restaurant)
                    .swipeActions {
                        Button(action: {
                            modelContext.delete(entry)
                            try? modelContext.save()
                        }, label: { Label("Delete", systemImage: "xmark") })
            }
        }
    }
}

总结

希望这篇文章对您有所帮助!我们会持续分享相关技术文章,敬请关注 。

特别感谢 Swift社区 编辑部的每一位编辑,感谢大家的辛苦付出,为 Swift社区 提供优质内容,为 Swift 语言的发展贡献自己的力量。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/737286.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【设计模式】设计模式前置知识:UML类图入门

UML类图 介绍 UML–Unified modeling language UMl(统一建模语言),是一种用于软件系统分析和设计的语言工具,它用于帮助软件开发人员进行思考和记录思路的结果UML本身是一套符号的规定,就像数学符号和化学符号一样,这些符号用于…

来啦!OceanBase 第7期技术征文活动获奖名单公布!

“小鱼”的诞生与成长离不开广大开发者的陪伴与支持,我们非常兴奋能把 4.1 版本的这一系列新能力带给大家,“小鱼”会游得更快更远,也会陪伴更多数据库开发者一同成长。 OceanBase 联合墨天轮技术社区,举行「4.1 上手体验」第五届…

基于SpringBoot+Hadoop+Vue的企业网盘系统

完整资料进入【数字空间】查看——baidu搜索"writebug" 1.1.1 选题的背景 随着信息网络技术的迅猛发展,云计算技术从它的概念提出已经开始在实际生产环境中使用了。大部分的东西都已经慢慢云端化,这种新型的技术也受到许多互联网人员的关注&a…

初阶C语言——三子棋

我们今天讲一个小游戏,三子棋大家应该都玩过吧,就是行和列,或者对角线上有一样大的字符时,就为获胜,今天我们就来写这样的一个代码实现这样的功能 首先我们要创建两个源文件和一个头文件 头文件game.h用来包含我们的头…

EmEditor制表符设置为空格

以下是具体操作 工具 - 当前配置属性 - 常规 - 制表符/缩进 - 将制表符转换为空格 前打对钩

作业怎么清除试卷笔迹?拿捏可以擦除答案的方法

在日常学习中,我们经常会遇到需要修改或擦除试卷上的笔迹的情况。本文将介绍一种简单实用的方法,即使用手机拍照扫描试卷并擦除答案。 手机拍照扫描试卷 首先,我们需要使用手机拍照扫描试卷。这一步非常简单,只需要将试卷平铺在桌…

集成学习-BaggingVoting和多个模型的混淆矩阵

当涉及到集成学习时,投票法和袋装法是两种常见的技术,用于将多个基学习器(base learner)组合成一个强大的集成模型。 投票法(Voting):投票法是一种简单且常用的集成学习方法。在投票法中&#…

Django_设置和读取cookie

设置cookie 在响应对象中使用set_cookie方法设置cookie from django.http import HttpResponsedef set_cookie(request):rsp HttpResponse("set cookie")rsp.set_cookie("set_cookie", "hello python", max_age3600)return rsp 注&#xff1…

Latex更改字体颜色以及快速生成 SCI 论文的 revised version 和 pure version

记录一下如何更改 Latex 字体颜色,在返修 SCI 论文时,如何较为快捷地完成 revised version 和 pure version 两个不同版本修改稿件的编辑与生成。 更改字体颜色 导入宏包 在 LaTeX 中,使用 \textcolor 命令或 \color 命令可以改变文本的颜…

十大机器学习算法之一:线性回归

十大机器学习算法之一:线性回归 1 知识预警1.1 线性代数1.2 矩阵微积分 2 什么是回归分析?3 线性回归3.1 一元线性回归3.2 多元线性回归 4 多项式回归 1 知识预警 1.1 线性代数 ( A T ) T A (A^\mathrm{T})^\mathrm{T}A (AT)TA$ ( A B ) T A T B T…

OpenHarmony社区运营报告(2023年6月)

本月快讯 • 6月12日,以“OpenHarmony共建开放,共享未来”为主题的2023开放原子全球开源峰会OpenAtom OpenHarmony(以下简称“OpenHarmony”)分论坛在北京北人亦创国际会展中心第一报告厅圆满落幕,根深叶茂&#xff0c…

【Java】面向对象编程 面向对象基础

一、面向对象基础 面向对象编程,是一种通过对象的方式,把现实世界映射到计算机模型的一种编程方法。 现实世界中,我们定义了“人”这种抽象概念,而具体的人则是“小明”、“小红”、“小军”等一个个具体的人。所以,…

uni-app 从零开始第三章:底部 tabBar

pages.json 页面路由 | uni-app官网 一、新建 home页面 找到pages目录,新增一个home的页面,勾选上同时新建文件夹 新建完成后,pages.json 中 会自动添加上刚刚新建的文件信息 二、新增tabBar数据 在 pages.json中新增以下代码 "tabB…

基于pyqt5实现一款简单的界面软件(radioButton、comboBox、pushButton、图片显示)

pyqt5使用记录涉及pyqt界面控件的基本介绍,使用designer设计界面ui,并将其转化为py代码。关于界面主要实现radioButton的互斥选中事件、comboBox的选中事件(依据list添加item)、pushButton的单击事件、槽函数自动绑定、图片的拖入…

嵌入式开发之上位机工业风界面实现

在做测控类的嵌入式系统开发时,一个精美的上位机控制软件UI是可以为系统增色不少,一般会采用组态软件来开发,我们来看看下面的界面 是不是非常直观有工业质感,还可以根据实时数据进行动态的显示和动画效果,那这些炫酷的…

自定义切换整行上下位置快捷键

自定义切换整行上下位置快捷键 在File菜单中选择Settings选项,搜索move li 先删掉原来的快捷键 再添加你要设置的快捷键 确认就可以了。

word转Markdown文件的几个方法

word转Markdown文件的几个方法 1、 安装writage 软件,但是writage 需要收费了。 如果只是markdown文本编辑,可以直接安装typora来。 2. 利用Pandoc软件来转换word文件到markdown文件 注意doc文件需要保存docx文件格式才可以使用下面命令行 pandoc &q…

C++多线程学习(十六、STL算法中的并行版本,sequenced_policy)

目录 sequenced_policy 使用代码: 准备 代码 结果: sequenced_policy 增加参数:sequenced_policy提供相应并行版算法 execution::seq并行算法执行可以不并行化execution::par并行算法执行可以并行化execution::par_unseq并行算法执行的可以并行以…

C#基础学习_泛型集合List<T>

C#基础学习_泛型集合List 为什么要使用集合? 数组元素个数是固定的,数组一旦定义,就无法改变元素总数。如果需求变化,则必须修改源码。 如果初始化元素总数非常大,则会造成浪费。 集合的特点: 根据需要动态增加元素个数,没有限制 List泛型集合的存储结构,与数组类似,…

Ceres-Solver 官方文档

Ceres-Solver 官方文档 Non-linear Least Squares1. Introduction2. Hello World!3. Derivatives3.1 Numeric Derivatives3.2 Analytic Derivatives3.3 More About Derivatives 4. Powell’s Function5. Curve Fitting6. Robust Curve Fitting7. Bundle Adjustment8. Other Exa…