CoreData数据库探索
CoreData是什么
Core Data 是苹果公司提供的一个对象-关系映射框架(Object-Relational Mapping,ORM),用于管理应用程序的数据模型。Core Data 提供了一个抽象层,使开发人员能够使用面向对象的方式访问和操作数据,而不需要直接与底层的数据库交互。Core Data 适用于管理复杂的数据模型,包括继承、关联和多对多关系。
Core Data 架构
CoreData 的架构由三个主要的部分组成:模型层、持久化层和控制层。
模型层
模型层是 CoreData 中的核心,它定义了应用程序中的数据模型。模型层由一个或多个实体组成,每个实体都代表了应用程序中的一个数据对象。实体由多个属性组成,每个属性代表了实体的一个特定数据项。
持久化层
持久化层负责将模型层中的数据保存到磁盘,并将这些数据重新加载到内存中。CoreData 支持多种持久化存储类型,包括 SQLite、XML 和二进制文件等。
控制层
控制层是 CoreData 的核心控制器,负责管理模型层和持久化层之间的交互。开发者可以使用控制器来执行各种操作,例如插入、更新、删除和查询数据等。
Core Data 主要由以下几个组件组成
- NSManagedObjectModel:用于描述数据模型的对象。数据模型由实体(Entity)、属性(Property)和关系(Relationship)等组成。NSManagedObjectModel 通过描述数据模型的方式,让 Core Data 知道如何将数据存储到底层的持久化存储中。
- NSManagedObjectContext:用于管理对象的上下文,负责对对象进行添加、删除、修改和查询等操作。NSManagedObjectContext 通常被认为是对象的容器,其中包含了对象的状态信息以及它们在持久化存储中的标识符。NSManagedObjectContext 还提供了事务支持,可以通过提交或回滚来管理对象的状态。
- NSPersistentStoreCoordinator:用于协调对象和底层的持久化存储之间的交互。NSPersistentStoreCoordinator 将 NSManagedObjectModel、NSPersistentStore 和 NSManagedObjectContext 连接起来,并提供了一系列方法,使开发人员能够在不同的持久化存储之间进行切换。
- NSPersistentStore:用于定义和管理持久化存储,包括 SQLite 数据库、二进制文件和 XML 文件等。NSPersistentStore 是 NSPersistentStoreCoordinator 的一个子类,用于将数据从 NSManagedObjectContext 持久化到底层存储中,或者从底层存储中读取数据到 NSManagedObjectContext 中。
Core Data常用工具
除了以上的核心组件之外,Core Data 还提供了一些其他的功能和工具,例如:
- NSFetchedResultsController:用于将 Core Data 查询结果直接绑定到 UITableView 或 UICollectionView 的数据源上,实现数据的自动刷新。
- NSFetchRequest:用于执行查询操作,支持各种查询条件和排序方式。
- NSManagedObject:所有 Core Data 实体的基类,表示一个被 Core Data 管理的对象。
- NSManagedObjectID:用于唯一标识一个被 Core Data 管理的对象。
- NSManagedObjectModelEditor:用于创建和编辑数据模型。
高效利用Core Data进行数据读写操作
使用Core Data进行数据读写操作时,可以考虑以下几点来提高效率:
- 使用批量操作:使用批量操作可以显著提高读写效率,避免频繁的读写磁盘。例如,可以使用NSBatchInsertRequest进行批量插入操作,使用NSBatchDeleteRequest进行批量删除操作。
- 合理使用缓存:Core Data提供了多级缓存,包括对象级别、上下文级别和持久化存储级别。可以通过设置合适的缓存策略来提高读写效率。
- 使用异步操作:可以使用Core Data的异步操作API,例如NSAsynchronousFetchRequest、NSAsynchronousSaveRequest等,将读写操作放在后台线程执行,避免阻塞主线程,提高用户体验。
- 优化数据模型:合理设计数据模型,避免冗余数据和不必要的关系,可以减少数据存储和读取时的开销。
- 使用轻量级迁移:当数据模型有变更时,使用轻量级迁移可以避免重新生成数据库和重新导入数据的开销,提高效率。
- 避免过度索引:索引可以提高查询效率,但是过度索引也会导致存储空间的浪费和写入性能的下降。需要根据实际情况,合理设置索引。
- 避免频繁的读写操作:频繁的读写操作会增加磁盘IO开销,降低读写效率。需要根据实际情况,合理设置读写操作的频率。
Core Data实现一个简单聊天功能
Core Data实现简单聊天功能可以分为以下几个步骤:
- 创建Core Data模型:在Xcode中创建一个Core Data模型文件,定义需要存储的实体以及它们的属性和关系。
- 设计数据结构:根据聊天功能的需求,设计需要存储的数据结构,比如消息内容、发送者、接收者、发送时间等信息。
- 添加数据:将新收到的消息或已发送的消息保存到Core Data数据库中。可以使用NSManagedObjectContext来创建和管理数据对象,NSManagedObject来表示一个Core Data实体对象。
- 查询数据:从Core Data数据库中查询消息记录,可以使用NSFetchRequest和NSPredicate来执行查询操作,将查询到的结果返回给界面展示。
- 更新数据:更新已有的消息记录,比如修改消息状态、删除消息等操作,同样使用NSManagedObjectContext进行处理。
- 实时更新:为了实现实时更新功能,可以使用NSFetchedResultsController来监听Core Data数据变化,一旦有新的消息记录,即可实时更新到聊天界面。
下面是一个简单的Swift代码示例,演示如何使用Core Data实现一个简单聊天功能:
// 创建Core Data模型
let modelURL = Bundle.main.url(forResource: "ChatModel", withExtension: "momd")
let model = NSManagedObjectModel(contentsOf: modelURL!)// 创建持久化存储协调器
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: model)
let storeURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("ChatDatabase.sqlite")
let options = [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true]
do {try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: storeURL, options: options)
} catch {print("Error creating persistent store: \(error)")
}// 创建托管对象上下文
let context = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
context.persistentStoreCoordinator = coordinator// 添加数据
let newMessage = NSEntityDescription.insertNewObject(forEntityName: "Message", into: context)
newMessage.setValue("Hello World!", forKey: "text")
newMessage.setValue(Date(), forKey: "timestamp")
newMessage.setValue(true, forKey: "isOutgoing")
try? context.save()// 查询数据
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Message")
let predicate = NSPredicate(format: "isOutgoing == %@", true as CVarArg)
request.predicate = predicate
let sortDescriptor = NSSortDescriptor(key: "timestamp", ascending: false)
request.sortDescriptors = [sortDescriptor]
let results = try? context.fetch(request)// 更新数据
if let message = results?.first as? NSManagedObject {message.setValue(false, forKey: "isOutgoing")try? context.save()
}// 实时更新
let fetchedResultsController = NSFetchedResultsController(fetchRequest: request, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
fetchedResultsController.delegate = self
try? fetchedResultsController.performFetch()
CoreData 线程安全
CoreData不是线程安全的。这意味着在多个线程中使用同一个NSManagedObjectContext可能会导致数据损坏或丢失。为了避免这种情况,我们应该在不同的线程中使用不同的NSManagedObjectContext实例。
在多线程环境下使用CoreData,我们可以使用NSManagedObjectContext的parent-child关系来管理多个上下文之间的数据共享和同步。子上下文可以在父上下文的基础上进行修改,这样可以避免在多个上下文之间进行数据共享和同步时出现冲突。
- 每个线程都应该拥有自己的 managed object context。不同的线程之间,不能共享同一个 context。通常来说,每个线程都需要自己的 context,而且在每个线程中只能使用自己的 context。
- 在多线程操作中,不要使用主线程的 managed object context。主线程的 context 应该用于主线程中的 UI 操作,而不应该在多线程中使用。
- 使用 child context。通过创建 child context,可以在子线程中执行一些数据操作,然后将结果保存到父 context 中。这样可以避免在主线程中执行一些长时间的数据操作。
- 尽量使用异步操作。对于一些比较耗时的数据操作,应该使用异步操作来避免阻塞主线程。
- 使用正确的 merge policy。合适的 merge policy 可以保证数据操作的正确性。在使用 merge policy 时,需要根据具体的业务需求来选择不同的策略。
- 使用正确的数据保存方式。对于一些需要频繁更新的数据,可以考虑使用 SQLite 的 WAL 模式。这样可以避免频繁的数据库锁等问题,提高数据操作的效率。
- 使用合适的数据结构。对于一些需要高效查询的数据,可以考虑使用索引等数据结构来提高查询效率。
- 避免一次性加载过多数据。如果一次性加载过多的数据,会导致内存占用过高,影响程序的性能。可以考虑使用分页等方式来避免这种情况。
相关文章:

CoreData数据库探索
CoreData是什么 Core Data 是苹果公司提供的一个对象-关系映射框架(Object-Relational Mapping,ORM),用于管理应用程序的数据模型。Core Data 提供了一个抽象层,使开发人员能够使用面向对象的方式访问和操作数据&…...

FreeRTOS入门
目录 一、简介 二、堆的概念 三、栈的概念 四、从官方源码中精简出第一个FreeRTOS程序 五、修改官方源码增加串口打印 一、简介 FreeRTOS是一个迷你的实时操作系统内核。作为一个轻量级的操作系统,功能包括:任务管理、时间管理、信号量、消息队列、…...

JVM运行时数据区划分
Java内存空间 内存是非常重要的系统资源,是硬盘和cpu的中间仓库及桥梁,承载着操作系统和应用程序的实时运行。JVM内存布局规定了JAVA在运行过程中内存申请、分配、管理的策略,保证了JVM的高效稳定运行。不同的jvm对于内存的划分方式和管理机…...

重装系统一半电脑蓝屏如何解决
小编相信大家在使用电脑或者给电脑重装系统的时候都遇到过电脑蓝屏等等故障问题。最近有用户就遇到了这样一个问题,问小编重装系统一半电脑蓝屏怎么办,那么今天小编就告诉大家重装系统一半电脑蓝屏的解决方法。 工具/原料: 系统版本&#x…...

SpringBoot(tedu)——day01——环境搭建
SpringBoot(tedu)——day01——环境搭建 目录SpringBoot(tedu)——day01——环境搭建零、今日目标一、IDEA2021项目环境搭建1.1 通过 ctrl鼠标滚轮 实现字体大小缩放1.2 自动提示设置 去除大小写匹配1.3 设置参数方法自动提示1.4 设定字符集 要求都使用UTF-8编码1.5 设置自动编…...

springboot整合redis
1.redis的数据类型,一共有5种.后面结合Jedis和redistemplate,以及单元测试junit一起验证 1)字符串 2)hash 3)列表 4)set(无序集合) 5)zset(有序集合) 2.Jedis的使用 a)引入依赖 <!--加入springboot的starter的起步依赖--><dependency><groupId>…...

【Java】Spring Boot下的MVC
文章目录Spring MVC程序开发1. 什么是Spring MVC?1.1 MVC定义1.2 MVC 和 Spring MVC 的关系2. 为什么学习Spring MVC?3. 怎么学习Spring MVC?3.1 Spring MVC的创建和连接3.1.1 创建Spring MVC项目3.1.2 RequestMapping 注解介绍3.1.3 Request…...

【项目精选】 塞北村镇旅游网站设计(视频+论文+源码)
点击下载源码 摘要 城市旅游产业的日新月异影响着村镇旅游产业的发展变化。网络、电子科技的迅猛前进同样牵动着旅游产业的快速成长。随着人们消费理念的不断发展变化,越来越多的人开始注意精神文明的追求,而不仅仅只是在意物质消费的提高。塞北村镇旅游…...

十、Spring IoC注解式开发
1 声明Bean的注解 负责声明Bean的注解,常见的包括四个: ComponentControllerServiceRepository Controller、Service、Repository这三个注解都是Component注解的别名。 也就是说:这四个注解的功能都一样。用哪个都可以。 只是为了增强程序…...

Linux系统GPIO应用编程
目录应用层如何操控GPIOGPIO 应用编程之输出GPIO 应用编程之输入GPIO 应用编程之中断在开发板上测试GPIO 输出测试GPIO 输入测试GPIO 中断测试本章介绍应用层如何控制GPIO,譬如控制GPIO 输出高电平、或输出低电平。应用层如何操控GPIO 与LED 设备一样,G…...

手敲Mybatis-反射工具天花板
历时漫长的岁月,终于鼓起勇气继续研究Mybatis的反射工具类们,简直就是把反射玩出花,但是理解起来还是很有难度的,涉及的内容代码也颇多,所以花费时间也比较浩大,不过当了解套路每个类的功能也好,…...

Java -数据结构,【优先级队列 / 堆】
一、二叉树的顺序存储 在前面我们已经讲了二叉树的链式存储,就是一棵树的左孩子和右孩子 而现在讲的是:顺序存储一棵二叉树。 1.1、存储方式 使用数组保存二叉树结构,方式即将二叉树用层序遍历方式放入数组中。 一般只适合表示完全二叉树&a…...

Python+Qt指纹录入识别考勤系统
PythonQt指纹录入识别考勤系统如需安装运行环境或远程调试,见文章底部个人QQ名片,由专业技术人员远程协助!前言这篇博客针对<<PythonQt指纹录入识别考勤系统>>编写代码,代码整洁,规则,易读。 学…...

K_A14_004 基于STM32等单片机驱动旋转角度传感器模块 串口与OLED0.96双显示
K_A14_004 基于STM32等单片机驱动旋转角度传感器模块 串口与OLED0.96双显示一、资源说明二、基本参数参数引脚说明三、驱动说明IIC地址/采集通道选择/时序对应程序:四、部分代码说明1、接线引脚定义1.1、STC89C52RC旋转角度传感器模块1.2、STM32F103C8T6旋转角度传感器模块五、…...

2023年全国最新机动车签字授权人精选真题及答案12
百分百题库提供机动车签字授权人考试试题、机动车签字授权人考试预测题、机动车签字授权人考试真题、机动车签字授权人证考试题库等,提供在线做题刷题,在线模拟考试,助你考试轻松过关。 11.注册登记前所有机动车都应进行安全技术检验。 答案…...
Linux小黑板(10):信号
我们写在linux系统环境下写一个程序,唔,"它的功能是每隔1s向屏幕打印hello world。"这时,我们在键盘上按出"Ctrl C"后,进程会发生什么??我们清晰地看到,进程已经在我们按出"Ctrl…...

GO 语言基础语法一 (快速入门 Go 语言)
Go语言基础语法一. golang 标识符,关键字,命名规则二. golang 变量三. golang 常量四. golang 数据类型五. golang 布尔类型六. golang 数字类型七. golang 字符串1. go语言字符串字面量2. go语言字符串连接(1). 使用加号(2). 使用 fmt.Sprintf() 函数(3…...

Java高效率复习-SpringMVC[SpringMVC-2]
SpringMVC获取请求参数 SpringMVC获取请求参数的两种方式↓ 通过ServletAPI获取请求参数 将HttpServletRequest作为控制器方法的形参,此时HttpServletRequest类型的参数表示封装了当前请求的请求报文的对象 通过request的API——getParameter(String s)方法来获取…...

【前端】一个更底层库-React基础知识点
目录Reat是什么?为什么要使用React类库比较容易学习,API非常少。组件内聚,容易组合原生组件和自定义组件融合渲染状态/属性驱动全局更新commonjs生态圈/工具栏完善React基础知识JSX概述JSX嵌入变量Event事件组合组合CHILDREN总结大家好&#…...

C++ 之枚举类型
文章目录参考描述枚举类型枚举类型枚举变量的声明及定义细节枚举常量的默认初始值枚举常量不可被修改赋值运算枚举常量与数据类型为枚举常量指定数据类型可选择的数据类型特殊的 Bool强枚举类型命名冲突强枚举类型参考 项目描述菜鸟教程C 枚举类型详解精通C (第九版…...

软件测试用例(3)
按照测试对象划分: 一)界面测试: 1)软件只是一种工具,软件和人的信息交流是通过界面来进行的,界面是软件和用户交流的最直接的一层,界面的设计决定了用户对于我们设计软件的第一映像,界面如同人的面孔,具有最吸引用户的…...

Spring——Bean管理-注解方式进行属性注入
Spring针对Bean管理中创建对象提供的注解有哪些?Component:普通Service:业务逻辑层Controller:controller层Repository:dao层用注解的方式是为什么?简化xml方式开发,只需要注解就可以完成在配置…...

【设计模式之美 设计原则与思想:设计原则】20 | 理论六:我为何说KISS、YAGNI原则看似简单,却经常被用错?
上几节课中,我们学习了经典的 SOLID 原则。今天,我们讲两个设计原则:KISS 原则和 YAGNI 原则。其中,KISS 原则比较经典,耳熟能详,但 YAGNI 你可能没怎么听过,不过它理解起来也不难。 理解这两个…...

Java代码弱点与修复之——Copy-paste error(复制粘贴错误)
弱点描述 Copy-paste error,复制粘贴错误。 是指在复制和粘贴代码时产生的错误。这种错误通常是由于程序员在复制代码时未正确编辑所复制的代码或编辑复制后的代码时忘记更改一些值或参数而导致的。复制粘贴错误可能会导致程序逻辑错误、编译错误或运行时错误。 示例代码 …...

Editor.md 的使用方法及图片处理
目录1. 资源下载2. 生成页面2.1 编辑和预览页面2.2 文本渲染页面3. 图片上传3.1 前端配置3.2 后端接口4. 图片粘贴[^2]1. 资源下载 官网下载 gitee 下载 2. 生成页面 2.1 编辑和预览页面 将资源(精简后 Editor.md 资源1)导入项目: 按照官…...

剑指 Offer II 018. 有效的回文
题目链接 剑指 Offer II 018. 有效的回文 easy 题目描述 给定一个字符串 s,验证 s是否是 回文串 ,只考虑字母和数字字符,可以忽略字母的大小写。 本题中,将空字符串定义为有效的 回文串 。 示例 1: 输入: s “A man, a plan, …...

Elasticsearch分析器(Analyzer)
Elasticsearch分析器(Analyzer) 文章目录Elasticsearch分析器(Analyzer)分析器概念内置分析器(8.6版本)自定义分析器elasticsearch-analysis-ik(简称ik,💕14.8kÿ…...
P6入门:了解P6 Professional 工具栏及地图分享
目录 引言 相关分享 引言 凭借更大的灵活性和增强的自定义功能,最新版本的 Oracle Primavera P6 Professional 的界面比早期版本有了巨大改进。对于有经验的伙伴来说,它仍然是熟悉的领域,几乎所有预期的功能都显示在前面。该界面可以更好地…...

习题30 if elif else 语句
people 30#变量people赋值30 cars 40#变量cars赋值40 buses 15#变量buses赋值 if cars > people:#如果出租车比人多print("We should take the cars")#我们坐出租车 elif cars < people:#elif后面必须跟条件,print("We should not take the…...

32 openEuler使用LVM管理硬盘-管理卷组
文章目录32 openEuler使用LVM管理硬盘-管理卷组32.1 创建卷组32.2 查看卷组32.3 修改卷组属性32.4 扩展卷组32.5 收缩卷组32.6 删除卷组32 openEuler使用LVM管理硬盘-管理卷组 32.1 创建卷组 可在root权限下通过vgcreate命令创建卷组。 vgcreate [option] vgname pvname ...…...