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) in
    if let error = error as NSError? {
        fatalError("Unresolved error \(error), \(error.userInfo)")
    }
})

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

import CoreData

struct PersistenceController {
    static let shared = PersistenceController()
    let container: NSPersistentContainer

    init(inMemory: Bool = false) {
        container = NSPersistentContainer(name: "CoredataTest")
        if inMemory {
            container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
        }
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if 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 = name
    student.age = age
    student.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 NSError
    fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}

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

//
//  Persistence.swift
//  CoredataTest
//

import CoreData

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

struct PersistenceController {
    static let shared = PersistenceController()

    static var preview: PersistenceController = {
        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 NSError
            fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
        }
        return result
    }()

    let container: NSPersistentContainer

    init(inMemory: Bool = false) {
        container = NSPersistentContainer(name: "CoredataTest")
        if inMemory {
            container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
        }
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if 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.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 NSError
        fatalError("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.shared

    var 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 CoreData

struct 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 in
                    NavigationLink {
                        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 NSError
                fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
            }
        }
    }
}

#Preview {
    ContentView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
}

在这里插入图片描述

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

wordpress模板官网

移民wordpress主题 移民代办wordpress主题&#xff0c;适合做海外移民咨询的代理公司搭建wordpress企业官方网站使用。 https://www.jianzhanpress.com/?p5130 夏令营wordpress主题 绿色夏令营wordpress主题&#xff0c;适合做夏令营或户外拓展的公司搭建wordpress官方网站…

【动态规划】第十一届蓝桥杯省赛第二场C++ C组《数字三角形》(c++)

1.题目描述 上图给出了一个数字三角形。 从三角形的顶部到底部有很多条不同的路径。 对于每条路径&#xff0c;把路径上面的数加起来可以得到一个和&#xff0c;你的任务就是找到最大的和。 路径上的每一步只能从一个数走到下一层和它最近的左边的那个数或者右边的那个数。 …

绝地求生:小团团曝被判8年:地图语音包或将下架,公会和主播被一锅端

这两天大家都在讨论某鱼平台办卡抽奖的事情。这件事发生之后没多久&#xff0c;某鱼平台里面的大量主播在同一时间停播&#xff0c;闲游盒认为大家应该也懂的&#xff0c;这次停播就是因为这些主播也参与了办卡抽奖&#xff0c;都需要接受调查&#xff0c;在两个月左右的调查中…

【项目实践】如何发掘用户隐性需求推送PUSH

1.背景 对比业界广告推荐、触达成熟的平台&#xff0c;例如抖音&#xff0c;小红书&#xff0c;淘宝&#xff0c;知乎等&#xff0c;都已经站在巨量数据的基础之上&#xff0c;具备了 “用户意图分析” 的能力&#xff0c;可以分析出 “用户的隐性需求”&#xff0c;假设我们同…

Python学习日记(一:List、Tuple、dictionary)

前言&#xff1a; 最近想拓展一下自己的知识面&#xff0c;特来学习一下python这门语言&#xff0c;因为之前学习过C语言&#xff0c;目前学习起来Python还不是特别费劲&#xff0c;也由此感叹C语言不愧是最基础的语言。不多废话&#xff0c;进入正题 概述&#xff1a; Pytho…

典中典之西电A测-气压测控仿真系统

兄弟,如果你看到这篇,只能说明你A测也挂了,没办法,哥们太菜了,抄的太假过不了你电有些老师的慧眼 这坨&#x1f415;⑩我先吃为敬 环境搭建可以参考这个兄弟的博客 一、题目要求 实现功能&#xff1a;使用 Arduino UNO 微控制器&#xff0c;搭建一个 PC 上位机远程气压检测控…

动态规划:LeetCode第10题 正则表达式匹配

题目&#xff1a; 给你一个字符串 s 和一个字符规律 p&#xff0c;请你来实现一个支持 . 和 * 的正则表达式匹配。 . 匹配任意单个字符* 匹配零个或多个前面的那一个元素 所谓匹配&#xff0c;是要涵盖 整个 字符串 s的&#xff0c;而不是部分字符串。 示例 1&#xff1a; …

C语言文件操作,linux文件操作,文件描述符,linux下一切皆文件,缓冲区,重定向

目录 C语言文件操作 如何打开文件以及打开文件方式 读写文件 关闭文件 Linux系统下的文件操作 open 宏标志位 write&#xff0c;read&#xff0c;close&#xff0c;lseek接口 什么是当前路径&#xff1f; linux下一切皆文件 文件描述符 文件描述符排序 C语言文件操…

【Linux从青铜到王者】进程信号

——————————————————————————————————————————— 信号入门 在了解信号之前有许多要理解的相关概念 我们可以先通过一个生活例子来初步认识一下信号 1.生活角度的信号 你在网上买了很多件商品&#xff0c;再等待不同商品快递的到来…

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

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

Python爬虫实战(基础篇)—13获取《人民网》【最新】【国内】【国际】写入Word(附完整代码)

文章目录 专栏导读背景测试代码分析请求网址请求参数代码测试数据分析利用lxml+xpath进一步分析将获取链接再获取文章内容测试代码写入word完整代码总结专栏导读 🔥🔥本文已收录于《Python基础篇爬虫》 🉑🉑本专栏专门针对于有爬虫基础准备的一套基础教学,轻松掌握Py…

vue 安装各种问题

新下载了个项目模板&#xff0c;安装包就遇到了各种各样问题 电脑&#xff1a;mac 使用npm i 等命令一直安装项目&#xff0c;然后一直报错 2534 info run canvas2.11.2 install node_modules/canvas node-pre-gyp install --fallback-to-build --update-binary 2535 info r…

Tomcat+Nginx的动静分离

1.反向代理多机 实验&#xff1a;Nginx要开启upstream(负载均衡)、location(url链接)、proxy_pass(反向代理) 配置&#xff1a;7-3做代理服务器&#xff1b;7-1 和 7-2做Tomcat服务器 关闭防火墙和selinux 1.准备配置 7-3安装nginx&#xff1b;7-1 和 7-2安装Tomcat&#xff…

Re61:读论文 PRP Get an A in Math: Progressive Rectification Prompting

诸神缄默不语-个人CSDN博文目录 诸神缄默不语的论文阅读笔记和分类 论文名称&#xff1a;Get an A in Math: Progressive Rectification Prompting ArXiv网址&#xff1a;https://arxiv.org/abs/2312.06867 官方实现网站&#xff1a;PRP 官方代码&#xff1a;https://github.…

iOS 17.0 UIGraphicsBeginImageContextWithOptions 崩溃处理

在升级到iOS17后你会发现&#xff0c;之前版本运行的很好&#xff0c;这个版本突然会出现一个运行闪退。报错日志为*** Assertion failure in void _UIGraphicsBeginImageContextWithOptions(CGSize, BOOL, CGFloat, BOOL)(), UIGraphics.m:410 跟踪到具体的报错位置如下所示&a…

闰年导致的哪些 Bug

每次闰年对程序员们都是一个挑战&#xff0c;平时运行好好的系统&#xff0c;在 02-29 这一天&#xff0c;好像就会有各种毛病。 虽然&#xff0c;提前一天&#xff0c;领导们都会提前给下面打招呼。但是&#xff0c;不可避免的&#xff0c;今天公司因为闰年还是有一些小故障。…

Tomcat(二) 动静分离

一、(TomcatNginx)动静分离 1、单机反向代理 利用 nginx 反向代理实现全部转发至指定同一个虚拟主机 客户端curl www.a.com 访问nginx服务&#xff0c;nginx服务通过配置反向代理proxy_pass www.a.com:8080&#xff0c;最终客户端看到的是www.a.com 实验中&#xff1a;7-3 做客…

码农世界:从入门到高手的成长攻略

&#x1f468;‍&#x1f4bb;&#x1f469;‍&#x1f4bb; 各位编程爱好者&#xff0c;欢迎来到现实而又充满挑战的码农世界。在这里&#xff0c;我们将一起探索一条如何从入门走向精通&#xff0c;最终在IT行业中找到自己位置的道路。准备好笔记本和热情&#xff0c;让我们携…

速通C语言第十三站 预处理

系列文章目录 速通C语言系列 速通C语言第一站 一篇博客带你初识C语言 http://t.csdn.cn/N57xl 速通C语言第二站 一篇博客带你搞定分支循环 http://t.csdn.cn/Uwn7W 速通C语言第三站 一篇博客带你搞定函数 http://t.csdn.cn/bfrUM 速通C语言第四站 一篇博客带…

STM32 NAND FLASH知识点

1.NAND FLASH的简介 NAND FLASH 的概念是由东芝公司在 1989 年率先提出&#xff0c;它内部采用非线性宏单元模式&#xff0c;为固态大容量内存的实现提供了廉价有效的解决方案。 NAND FLASH 存储器具有容量较大&#xff0c;改写速度快等优点&#xff0c;适用于大量数据的存储&…