SwiftUI之CoreData详解(一)

coreData 是一种数据持久化的方案,是对SQLite的一种封装。一说到这种桌面化的数据库,我就无比的怀念Foxbase|Foxpro, 多好的数据库产品,被微软扼杀了,相当年教大学生妹子们国家二级数据库时都是手把手教的,呃~~~,不好意思,说的有点跑题了。要想使用coreData, 首先我们要先创建一个模型文件,它是一个.xcdatamodeld结尾的文件,这个模型文件说白了就是一个库,是的,因为coreData的本质就是一个关系数据库模型,只不过在这里把各种名称改了个名字而已(题外话,苹果公司以为这样做更显得更高大上,依我看其实真没这个必要,只会增加开发者的学习负担)。数据表也不叫数据表,叫实体(entity), 字段也不叫字段,叫属性(atributte),你看,苹果就是这么的特立独行,没办法,谁让它的系统设计的那么的招人爱呢。其实这些叫法都没问题,因为在关系数据库中这个名词都是合法的,只是大部分开发者习惯了一种规则。
首先,我们创建项目coreDataTest
在这里插入图片描述

Storage中创建 coreData, 关于swiftData,我会在后面的文章个讲解,因为这个需要最新的系统才能使用。
在这里插入图片描述

如果没有选也没关系,也可以手动创建,只不过会麻烦一些,选择后系统会给我们自动创建一些代码。
在这里插入图片描述

下一步在选择保存目录时如果勾选 Create Git repository on my Mac, 则创建项目的同时会创建 git 仓库。 关于 git 仓库的使用请查看我往期的文章。

这样我们的项目就创建好了,在项目中会有一个 coreDataTest.xcdatamodeld的文件,这个就是coredata的模型文件,也就是本地数据库文件。
在这里插入图片描述

如果是手动创建,请看下面的步骤:

创建模型

一般在创建项目的开始,如果你勾选了 coreData 这个选项,那么你的项目中就有一个和项目同名的 .xcdatamodeld ,如何你没有选择,那么我们就要创建它。创建它很简单,通过 文件 -> 新建 -> 文件 -> Data Model创建一个模型, 如下所示:
在这里插入图片描述

在底部有两个按钮,一个在左侧是 addEntity 用于增加新的实体(数据表格), 一个在右侧是 add Attribute 用于添加一个属性(字段)。我们点击 addEntity 增加一个数据表, 然后双击表名修改名称,名称的第一个字符一定要大写。 要想删除一个数据表,直接按键盘上的 delete

添加实体与属性

默认的有一个Item实体了,做为测试,我们再创建一个 Student 的实体,并添加以下属性:

  • id: UUID
  • name: String
  • age: Int16
  • sex: Int16

如下所示:
在这里插入图片描述

目前关于其它功能暂时不用管它。现在一个基本的数据库已经设计好了,下面我们看看如何使用它。

访问控制器

coreData 要用一个控制器才能访问它,也叫上下文容器, 这个容器类型为 NSPersistentContainer

如下所示:

let container: NSPersistentContainer
container = NSPersistentContainer(name: "CoredataTest")

NSPersistentContainer(name: "CoredataTest")里面传的就是我们数据模型文件的名称,可以有多个数据模型,只要把相应的名称传给它就行了,这样我们就有了引用这个数据模型的上下文,也就是数据环境。如果我们想让这个数据模型存在内存里而不是文件中,那么就要这么设置:

container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")

然后就是加载数据了:

container.loadPersistentStores(completionHandler: { (storeDescription, error) inif let error = error as NSError? {fatalError("Unresolved error \(error), \(error.userInfo)")}
})

闭包中的 storeDescription 是路径信息, error 是异常详情。根据以上内容,我们封装一下:

import CoreDatastruct PersistenceController {static let shared = PersistenceController()let container: NSPersistentContainerinit(inMemory: Bool = false) {container = NSPersistentContainer(name: "CoredataTest")if inMemory {container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")}container.loadPersistentStores(completionHandler: { (storeDescription, error) inif let error = error as NSError? {fatalError("Unresolved error \(error), \(error.userInfo)")}})container.viewContext.automaticallyMergesChangesFromParent = true}
}

这样一个数据的控制器就创建好了,我们现在来创建一些数据存储一下, 由于属性是相同的,我们这里创建一个函数:

func addStudent(viewContext: NSManagedObjectContext, name: String, age: Int16, sex:Int16 = 1){let student = Student(context: viewContext)student.id = UUID()student.name = namestudent.age = agestudent.sex = age
}

然后像这样调用:

let result = PersistenceController(inMemory: true)
let viewContext = result.container.viewContext
addStudent(viewContext: viewContext, name: "张三", age: 23, sex: 1)
addStudent(viewContext: viewContext, name: "李四", age: 26, sex: 1)
addStudent(viewContext: viewContext, name: "王二", age: 19, sex: 2)
addStudent(viewContext: viewContext, name: "麻子", age: 20, sex: 2)
addStudent(viewContext: viewContext, name: "刘七", age: 29, sex: 1)
do {try viewContext.save()
} catch {let nsError = error as NSErrorfatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}

大至的过程我们已经清楚了,现在我们来整合一下,创建一个swift文件,这个文件名没有特别要求,建议以大写开头的文件名,这里用系统给定的名称:Persistence.swft

//
//  Persistence.swift
//  CoredataTest
//import CoreDatafunc addStudent(viewContext: NSManagedObjectContext, name: String, age: Int16, sex:Int16 = 1){let student = Student(context: viewContext)student.id = UUID()student.name = namestudent.age = agestudent.sex = age
}struct PersistenceController {static let shared = PersistenceController()static var preview: PersistenceController = {let result = PersistenceController(inMemory: true)let viewContext = result.container.viewContextaddStudent(viewContext: viewContext, name: "张三", age: 23, sex: 1)addStudent(viewContext: viewContext, name: "李四", age: 26, sex: 1)addStudent(viewContext: viewContext, name: "王二", age: 19, sex: 2)addStudent(viewContext: viewContext, name: "麻子", age: 20, sex: 2)addStudent(viewContext: viewContext, name: "刘七", age: 29, sex: 1)do {try viewContext.save()} catch {let nsError = error as NSErrorfatalError("Unresolved error \(nsError), \(nsError.userInfo)")}return result}()let container: NSPersistentContainerinit(inMemory: Bool = false) {container = NSPersistentContainer(name: "CoredataTest")if inMemory {container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")}container.loadPersistentStores(completionHandler: { (storeDescription, error) inif let error = error as NSError? {fatalError("Unresolved error \(error), \(error.userInfo)")}})container.viewContext.automaticallyMergesChangesFromParent = true}
}

如果你在创建项目的开始选择了coreData,其实这个文件会自动创建。只是为了后面的实例我做了少许的改动。上面的结构代码中的如下代码

static var preview: PersistenceController = {let result = PersistenceController(inMemory: true)let viewContext = result.container.viewContextaddStudent(viewContext: viewContext, name: "张三", age: 23, sex: 1)addStudent(viewContext: viewContext, name: "李四", age: 26, sex: 1)addStudent(viewContext: viewContext, name: "王二", age: 19, sex: 2)addStudent(viewContext: viewContext, name: "麻子", age: 20, sex: 2)addStudent(viewContext: viewContext, name: "刘七", age: 29, sex: 1)do {try viewContext.save()} catch {let nsError = error as NSErrorfatalError("Unresolved error \(nsError), \(nsError.userInfo)")}return result
}()

是为预览做的准备数据。如果你不想预览,只想实时真机调试的话这个可以省略。

container.viewContext.automaticallyMergesChangesFromParent = true

这句的作用是实时的将数据的变动反映到Context中。也就是实时刷新的意思。

从上面的可以看出,要想操作coreData, 就必须先获取这个控制器的context, 即上下文。做为程序的单列执行环境,我们可以把它存到环境变量中,以方便不同的程序获取。所以,我们在项目的App中(即入口程序)把这个句柄注册到环境变量中:

CoredataTestApp.swift

//
//  CoredataTestApp.swift
//  CoredataTest
//import SwiftUI@main
struct CoredataTestApp: App {let persistenceController = PersistenceController.sharedvar body: some Scene {WindowGroup {ContentView().environment(\.managedObjectContext,persistenceController.container.viewContext)}}
}

这样,我们在 ContentView视图中就可以直接这样获取到这个context:

@Environment(\.managedObjectContext) private var viewContext

为了简化流程,现在的问题就差一个,就是如何把数据反映到我们的UI中来,这就要用到查询语句了,当然这是swiftUI中封装好的。

@FetchRequest(sortDescriptors: [NSSortDescriptor(keyPath: \Student.id, ascending: true)],animation: .default)
private var items: FetchedResults<Student>

我们把@FetchRequest当作是变量的申明注解就行了。keyPath是用于唯一标识的id号,只要是能唯一标识数据记录就行, 这样items就是所有数据的集合了。

ContentView.swift

//
//  ContentView.swift
//  CoredataTest
//import SwiftUI
import CoreDatastruct ContentView: View {@Environment(\.managedObjectContext) private var viewContext@FetchRequest(sortDescriptors: [NSSortDescriptor(keyPath: \Student.id, ascending: true)],animation: .default)private var items: FetchedResults<Student>var body: some View {NavigationView {List {ForEach(items) { item inNavigationLink {Text("学生 在 \(item.id!)")} label: {Text(item.name!)}}.onDelete(perform: deleteItems)}}}private func deleteItems(offsets: IndexSet) {withAnimation {offsets.map { items[$0] }.forEach(viewContext.delete)do {try viewContext.save()} catch {let nsError = error as NSErrorfatalError("Unresolved error \(nsError), \(nsError.userInfo)")}}}
}#Preview {ContentView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
}

在这里插入图片描述

当然,这只是开胃小菜,好戏还没上场。

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

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

相关文章

Java轻量延迟重试队列实现

背景 很多开放平台都使用Webhook的方式进行外部系统数据同步或者通知&#xff0c;对于Webhook请求的对外发送不进行重试显然有点说不过去。使用简单的while一个条件去重试N次好像达不到什么效果&#xff0c;只能是说有重试而已&#xff0c;而使用消息队列中间件好像依赖又太重…

【论文阅读】High-Resolution Image Synthesis with Latent Diffusion Model

High-Resolution Image Synthesis with Latent Diffusion Model 引用&#xff1a; Rombach R, Blattmann A, Lorenz D, et al. High-resolution image synthesis with latent diffusion models[C]//Proceedings of the IEEE/CVF conference on computer vision and pattern re…

SkyWalking链路追踪上下文TraceContext的追踪身份traceId生成的实现原理剖析

结论先行 SkyWalking 通过字节码增强技术实现&#xff0c;结合依赖注入和控制反转思想&#xff0c;以SkyWalking方式将追踪身份traceId编织到链路追踪上下文TraceContext中。 是不是很有趣&#xff0c;很有意思&#xff01;&#xff01;&#xff01; 实现原理剖析 TraceConte…

1.1_2 性能指标——速率、带宽、吞吐量

文章目录 1.1_2 性能指标——速率、带宽、吞吐量&#xff08;一&#xff09;速率&#xff08;二&#xff09;带宽&#xff08;三&#xff09;吞吐量 1.1_2 性能指标——速率、带宽、吞吐量 &#xff08;一&#xff09;速率 速率即数据率或称数据传输率或比特率。 速率就是“快…

Redis的设计与实现

Redis的设计与实现 数据结构和内部编码 type命令实际返回的就是当前键的数据结构类型&#xff0c;它们分别是&#xff1a;string(字符串)hash(哈希)、list(列表)、set(集合)、zset (有序集合)&#xff0c;但这些只是Redis对外的数据结构。 实际上每种数据结构都有自己底层的…

Docker Protainer可视化平台,忘记登录密码,重置密码。

由于好久没有登录portainer系统&#xff0c;导致忘记了登录密码&#xff0c;试了好多常用的密码都不对&#xff0c;无奈只能重置密码。 一、停止protainer 容器 查看容器ID和COMMAND 用于停止容器 docker ps -a停止容器 docker stop portainer二、查找volume data 宿主机所在…

JavaEE之多线程

一.认识线程 1.多进程实现并发编程的不足之处&#xff1a; 引入多个进程的核心&#xff1a;实现并发编程&#xff08;c的CGI技术就是通过多进程的方式实现的网站后端开发&#xff09;。因为现在是一个多核cpu的时代&#xff0c;并发编程就是刚需。多进程实现并发编程&#xf…

达梦、金仓、南大、瀚高、优炫:从社区建设看企业技术自信心

正文约950字&#xff0c;预计阅读时间2分钟 国产技术厂商在面对自身产品问题时&#xff0c;往往保持回避态度&#xff0c;不愿公之于众&#xff0c;主要原因有2方面&#xff1a; 1&#xff0c;产品技术层面问题较多&#xff0c;如某些根本性缺陷难以攻克&#xff0c;或问题发…

java找工作之Mybatis(入门及xml配置相关)

Mybatis 学习Mybatis就要学会查看官网&#xff0c;官网地址如下&#xff1a;<MyBatis中文网 > 1、简介 1.1什么是Mybatis MyBatis 是一款优秀的持久层框架&#xff0c;它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取…

【Vue3】3-6 : 仿ElementPlus框架的el-button按钮组件实

文章目录 前言 本节内容实现需求完整代码如下&#xff1a; 前言 上节,我们学习了 slot插槽&#xff0c;组件内容的分发处理 本节内容 本小节利用前面学习的组件通信知识&#xff0c;来完成一个仿Element Plus框架的el-button按钮组件实现。 仿造的地址&#xff1a;uhttps://…

预充电阻器选型报告

1. 客户基础条件 预充时间 t≤200ms &#xff0c;电容 C1280uf &#xff0c;电池包最高电压 U410V&#xff0c;预充深度 98% &#xff0c;30 秒内连续预充 15 次。 1.1 现选型号 现选EAK预充电阻额定功率 60W&#xff0c;标称阻值为 35Ω&#xff0c;在 此条件下单次预充…

Unity 协程(Coroutine)到底是什么?

参考链接&#xff1a;Unity 协程(Coroutine)原理与用法详解_unity coroutine-CSDN博客 为啥在Unity中一般不考虑多线程 因为在Unity中&#xff0c;只能在主线程中获取物体的组件、方法、对象&#xff0c;如果脱离这些&#xff0c;Unity的很多功能无法实现&#xff0c;那么多线程…

红黑树的简单介绍

红黑树 红黑树的概念 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在每个结点上增加一个存储位表示结点的颜色&#xff0c;可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制&#xff0c;红黑树确保没有一条路径会比其他路径长出俩倍&#x…

Python类 __init__() 是一个特殊的方法

设计者&#xff1a;ISDF工软未来 版本&#xff1a;v1.0 日期&#xff1a;2024/3/5__init__() 是一个特殊的方法 类似c# C的构造函数 两头都包含两个下划线&#xff0c;这是约定&#xff0c;用于与普通的函数保持区分class User:用户类def __init__(self,first_name,last_name):…

Linux 运维:CentOS/RHEL防火墙和selinux设置

Linux 运维&#xff1a;CentOS/RHEL防火墙和selinux设置 一、防火墙常用管理命令1.1 CentOS/RHEL 7系统1.2 CentOS/RHEL 6系统 二、临时/永久关闭SELinux2.1 临时更改SELinux的执行模式2.2 永久更改SELinux的执行模式 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;…

Finetuning Large Language Models: Sharon Zhou

Finetuning Large Language Models 课程地址&#xff1a;https://www.deeplearning.ai/short-courses/finetuning-large-language-models/ 本文是学习笔记。 Goal&#xff1a; Learn the fundamentals of finetuning a large language model (LLM). Understand how finetu…

STM32(16)使用串口向电脑发送数据

发送字节 发送数组 发送字符和字符串 字符&#xff1a; 字符串&#xff1a; 字符串在电脑中以字符数组的形式存储

ElasticSearch之分布式模型介绍,选主,脑裂

写在前面 本文看下es分布式模型相关内容。 1&#xff1a;分布式模型 1.1&#xff1a;分布式特征 支持水平扩展&#xff0c;可以存储PB级别数据&#xff0c;每个就能都有自己唯一的名称,默认名称时elasticsearch&#xff0c;可以通过配置文件&#xff0c;如cluster.name: my…

PowerBI怎么修改数据库密码

第一步&#xff1a;点击转换数据 第二步&#xff1a;点击数据源设置 第三步&#xff1a;点击编辑权限 第四步&#xff1a;点击编辑 第五步&#xff1a;输入正要修改的密码就可以了

STM32启动过程及反汇编

STM32从Flash启动的过程&#xff0c;主要是从上电复位到main函数的过程&#xff0c;主要有以下步骤&#xff1a; 1.初始化堆栈指针 SP_initial_sp&#xff0c;初始化 PC 指针Reset_Handler 2.初始化中断向量表 3.配置系统时钟 4.调用 C 库函数_main 初始化用户堆栈&#xf…