Tag: 核心数据

在核心数据中使用可变类型作为可转换属性的危险

至此,我们已经建立了数据模型。 现在介绍建立符合NSCoding的可变数据类型’ UnpredicatbleValue ‘的部分。 此数据类型具有一个变量存储的属性,称为Int类型的’ value ‘ 。 实现如下: 现在,我们可以为我们的TransformableContainer实体创建NSManagedObject子类。 该类的实现如下: 现在,请仔细阅读以下说明。 注意 :如果将托管对象引用的值/对象替换为全新的值/对象 ,则Core Data会将托管对象视为已更改。 据说, 管理对象有未决的更改 。 现在,在上下文中调用save时,将保存下一次具有待处理更改的受管对象。 但是,如果您有一个由托管对象指向的对象,并且更改了objects 变量 (更改了对象的状态),则Core Data不知道它已被更改 。 因此, 托管对象未标记为具有挂起的更改 。 下次在上下文中调用保存时,将不会保存此类对象。 如果您已阅读以上说明,我们现在可以通过实际测试来证明这一点。 让我们打开ViewController.swift并编写以下代码: 如您所见,我们在viewDidLoad()中执行以下操作 从appDelegate的persistentContainer获取viewContext 。 在第一个do块中,我们将TransformableContainer插入到viewContext中。 该值设置为3 ,然后在viewContext上执行保存。 在第二个do块中,我们获取TransformableContainer。 将值更改为4并执行保存。 在第三个do块中,我们获取TransformableContainer。 打印值。 在第四个do块中,我们获取TransformableContainer。 我们从上下文中删除它并执行保存。 现在我们认为将值更改为4并执行保存后,应该将4保存为该值。 显然不是这样。 当该值实际为3时,我们会感到无礼。在控制台中,我们将获得以下日志。 值设为3 值从3变为4 transformableContainer.transformableAttribute.value:3 在考虑使用可变形属性时,请记住上面的注释 。 如果将可变类型用作可转换属性,则将面临危险。 您可以通过为Transformable属性使用非可变类型来避免这种情况。 如果不完全替换对象,则无法更改该值。 如果替换了对象,CoreData会知道它已更改,并将拥有的托管对象标记为具有挂起的更改。 […]

掌握CoreData(第4部分,面向核心数据对象的CRUD)

为了使用面向对象的方式演示核心数据的基础,让我们使用之前的项目,使其以面向对象的方式执行CRUD操作,因为我们需要将NSManagedObject子类化。 请按照以下步骤使用Xcode创建Core Data管理的对象子类: 在项目导航器中选择您的Core Data模型。Xcode在编辑器区域的大纲视图中显示所有实体。 在大纲视图中选择一个实体,然后验证是否在Data Model检查器中将Codegen弹出菜单设置为Manual / None,如图1所示。对于要创建Core Data受管对象子类的所有实体,请重复此步骤。 由于我们只有一个实体任务,因此我们在任务实体上执行了此任务。 选择Editor> Create NSManagedObject Subclass…,如图2所示。 在显示的工作表中,选择包含您的实体的数据模型,然后单击“下一步”。 图3从列表中选择数据模型。 在出现的工作表中,选择要创建其Core Data托管对象子类的实体,然后单击“下一步”。 图4从列表中选择您的实体。 在出现的工作表中,选择一个保存文件的位置,然后单击Create,如图5所示。 Xcode在所选位置为每个所选实体创建并保存名为ClassName + CoreDataClass和ClassName + CoreDataProperties的文件,其中ClassName是实体的NSManagedObject子类的名称。 ClassName + CoreDataClass实现NSManagedObject子类,如图6所示。 ClassName + CoreDataProperties实现ClassName + CoreDataClass扩展(对于Swift应用程序)或类别(对于Objective-C应用程序),如图7所示。 以面向对象的样式创建记录到核心数据 以面向对象的样式从核心数据中获取记录 从面向对象样式的核心数据中删除记录 摘要 我们只是以对象样式的方式完成了CRUD操作。 正如我们在第1部分中所述。 核心数据以一种看起来非常面向对象的方式存储我们的代码。 实体是指类,属性是指var,关系是指var指向其他类 接下来是什么? 在下一部分中,我们将讨论实体之间的关系。 有用的链接 https://store.raywenderlich.com/products/core-data-by-tutorials https://www.objc.io/issues/4-core-data/core-data-overview/ https://zh.wikipedia.org/wiki/Object-relational_mapping https://cocoacasts.com/what-are-core-data-entities-and-attributes https://cocoacasts.com/what-is-the-core-data-stack https://developer.apple.com/library/archive/documentation/DataManagement/Devpedia-CoreData/coreDataStack.html https://medium.com/@ankurvekariya/core-data-crud-with-swift-4-2-for-beginners-40efe4e7d1cc https://www.raywenderlich.com/7569-getting-started-with-core-data-tutorial https://developer.apple.com/library/archive/qa/qa1952/_index.html

掌握CoreData(第8部分:验证核心数据)

核心数据 ,使您可以将验证逻辑放入托管对象模型中并指定最常见的约束,而不是在代码中编写验证逻辑。 将数据转储到持久性存储之前 ,您可以对对象应用验证。 如果对象遵循约束,则上下文数据将成功持久保存,否则它将引发错误。 添加约束是开发人员的责任。 该框架具有许多用于在将对象持久化到磁盘之前对其进行验证的API。 在本教程中,我将向您展示Core Data为开发人员提供的验证对象的选项。 在第2部分中,我们写了这一点 托管对象上下文(MOC) 它提供缓存,更改跟踪,延迟加载,重做,撤消和验证功能 验证在核心数据中如何工作 验证约束仅在保存操作期间或在请求时由Core Data应用。 (您可以在对您的应用程序流程有意义的任何时候直接调用验证方法) 入门 您可以在此处下载启动程序项目。 该项目是教程的继续,请参见第5部分和第7部分,我们在其中创建了该项目。 如果您遵循以前的教程,请先删除该应用程序,然后再开始执行任何操作 属性验证 转到CrudOperationCoreData.xcdatamodeld→点击用户实体→双击firstName属性→在右侧的模型检查器中添加验证。 我们添加了firstName的两个验证最小和最大长度,还添加了默认值,如图1所示。确保选中了最大和最小长度复选框。 让我们深入研究代码并检查验证是否有效。 如您所见,当我们创建用户实体时, 默认值被分配给firstName属性,并且当我们使用12个以上的字符更新firstName值时,它在内存中的上下文中成功更新,但是当我们尝试将更改提交到持久性存储时,它将检查首先进行验证,如果验证失败,则会抛出错误,如图2所示 。 您可以在对实体本身调用save方法throw validateForInsert()和validateForUpdate()实例方法之前请求验证,并且可以覆盖此方法以对代码应用自定义验证。 我们将在本部分的最后一部分中查看自定义验证 日期验证 您可以在Date上应用最小和最大验证,如图3所示。 确保应选中“最小和最大日期”复选框,否则验证将不起作用。 关系验证 关系与属性没有很大的不同。 它们也可能受到约束。 关系可以是可选的,也可以是必需的。 一对多关系的计数可以限制为最小值和最大值 。 转到CrudOperationCoreData.xcdatamodeld →在用户实体上点击→在任务关系属性上点击→在​​模型检查器中,添加最小和最大验证,如图4所示。 首先删除该应用程序,并在User对象上添加三个 任务 ,如图5所示。 当我们尝试保存它时。 因为我们为单个User对象限制(两个)添加了max task对象,所以我们将添加三个,这将引发如图6所示的错误。 它在内存中的上下文上成功添加了三个任务,但是当我们尝试将更改(使用save()方法)提交给持久性存储时,它将首先检查验证,如果验证失败,则会抛出错误,如图6所示 。 您可以在对实体本身调用save方法throw validateForInsert()和validateForUpdate()实例方法之前请求验证,并且可以覆盖此方法以对代码应用自定义验证。 我们将在本部分的最后一部分中查看自定义验证 正则表达式验证 现在,我们将探讨如何在模型检查器核心数据中添加正则表达式。 我们将对用户的firstName属性应用正则表达式,该属性将允许至少一个字符,并且该字符将为小写 […]

可编码的NSManagedObject Coredata

在这里,我想分享一下我在Swift 4中使用可编码协议将JSON文件成功转换为CoreData NSManagedObjects的经验,从而避免了笨拙的聚合器层。 因此,想法是获取JSON数据并将其解码为NSManagedObjects Person对象和Car对象 步骤1:选择xcdatamodel,然后为Person ManagedObject和Car ManagedObject单击Editor-> Create NSManagedObject Subclass。 注意:在xcdatamodel中定义Person和Car对象之间的一对多关系 步骤2:现在是时候让Person ManagedObject类符合可编码协议了。 让我们看一下Person ManagedObject的示例。 您还必须对Car NSManagedObject类采用相同的协议。 请注意,在可解码协议中,汽车对象的类型为NSSet。 所以将数组类型转换为NSSet 步骤3:对Car Managed Object类重复上述步骤 步骤4:写入CoreData 瓦拉,就是这样。 您已经掌握了将JSON转换为CoreData Objects的知识。 如有查询,请随时通过pratheesh_db@hotmail.com与我联系。

在Swift 4中探索可编码和核心数据

也可以在我的投资组合网站PXPGraphics.com上阅读此博客文章。 最近,我曾在LinkedIn和Twitter上询问iOS社区,是否创建允许Core Data在Swift 和 Objective-C中支持Codable的框架是否有价值: 为了简化此数据流,应在应用程序体系结构中将数据,缓存和持久性逻辑抽象到它们自己的层中-这是提出的框架Badger(?)的目的 ,我希望在2019年发布。例如,提议的框架的一些目标包括: JSON序列化 模型验证 对象图管理 内存中缓存 磁盘上的持久性 记录和错误处理 由于该框架承担着许多责任,因此我决定将这些组件分解为本博客系列,标题为Exploring Codable and Core Data 。 为了帮助降低读者的入门门槛,我决定将重点放在每个帖子的几个基本主题上。 该系列将包括以下主题: Codable入门 使用可解码的解码自定义类型 使用可编码的自定义类型编码 (快来了) 核心数据入门 (快来了) 使核心数据成为您的模型层 (快来了) 创建您的核心数据栈 (快来了) 将可编码模型保存到核心数据 (快来了) 从核心数据获取可编码模型 (快来了) 测试可编码模型 (快来了) 测试核心数据模型 (快来了) 注意:我坚信以这种方式共享知识可以帮助来自不同经验和背景的各个级别的读者学习和提高他们的技能,并帮助社区发展壮大。 因此,您的任何反馈,问题或意见将不胜感激。 在此先感谢您,并随时关注更新!

掌握CoreData(第7部分核心数据关系删除规则)

正如我们在第5部分和第6部分中讨论的,当我们创建实体之间的关系时。 每个实体NSManagedObject与一个实体描述(NSEntityDescription的一个实例)相关联,该实体描述提供有关对象的元数据。 对象元数据包括对象代表的实体的名称以及其属性和关系的名称。 创建关系时,应考虑许多事项,删除规则就是其中之一。 删除规则 删除规则是使用Core Data的一大便利。 每个关系都有删除规则。 它定义了删除拥有关系的记录时发生的情况。 要么 关系的删除规则指定了尝试删除源对象时应该发生的情况。 在这一部分中,我们将使用之前的实体来了解删除规则。 下载Todo应用程序。 首先我们将做一些理论上的部分,然后我们将使用实际编码对其进行测试 核心数据支持四种删除规则:“层叠”,“拒绝”,“无效”和“不执行操作”。 级联 删除源时,请删除关系目标处的对象。 如果我们删除用户,则与该用户关联的所有任务也将被删除 要添加实体之间的关系,请参阅第5部分和第6部分。转至受管理对象模型文件,并使User → Task关系级联,如图1所示。 让我们创建一个具有两个todo 任务的 U ser ,如图2所示。如果您不理解此代码,请参阅第5部分和第6部分,其中我逐步讨论了该代码。 此代码将创建一个具有两个与之关联的待办事项的用户 ,并将其保存到磁盘 受管对象上下文视觉映射如图3所示。 通过仅向用户调用删除代码。 由于用户 → 任务删除规则是通过删除用户对象而级联的,因此它将删除与其相关联的所有任务 。 如您在控制台上看到的,没有任务对象剩余。 删除操作后的受管对象上下文的可视化映射如图4所示。您可以看到, 用户和与其关联的两个任务也从上下文中删除,并且通过调用save()方法,它也将从持久性存储中删除。 无效化 如果将关系的删除规则设置为Nullify ,则在删除记录时该关系的目标将无效,但目标对象仍然存在,仅源和目标之间的关系将被删除 首先将级联关系从下拉菜单更改为Nullify ,如图5所示。 让我们创建一个具有两个待办事项的U ser ,如图2所示。如果您不理解此代码,请参阅第5和第6部分,其中我逐步讨论了该代码。 此代码将创建一个具有两个与之关联的待办事项的用户 ,并将其保存到磁盘 托管对象上下文的可视化映射将如图6所示。 通过删除User对象,它不会删除与用户相关的任务,因为您可以看到我们仍添加在Managed Object Context中并打印在控制台中的两个任务,如图7所示。 托管对象上下文的可视化映射如图8所示。您可以看到因为User → Task具有相反的关系,在应用删除代码之前Task也引用了User对象。在删除User对象之后,此关系设置为nil如下所示 拒绝 […]

Swift 4中的可编码NSManagedObject(核心数据)和CLLocation

在进入主题之前,让我们先讨论一下编码。 可编码 CODE是Swift 4的新功能。它是Decodable协议的类型别名 和可编码协议。 typealias可编码=可分解和可编码 可以反序列化Decodable符合的枚举/结构/类。 例如,将json对象反序列化为结构。 // 宣言 struct Person:可分解{ 命名:字符串 } //反序列化 让jsonString =“”“ { “名称”:“郑正祥” } “” 如果让jsonData = jsonString.data(使用:.utf8){ 让人=尝试? JSONDecoder()。decode(Person.self,来自:jsonData) } Encodable遵循的 enum / struct / class可以序列化。 例如,一个结构被序列化为一个json对象。 // 宣言 结构人:可编码{ 命名:字符串 } //序列化 let person = Person(姓名:“郑正祥”) 让jsonData =试试吗? JSONEncoder()。encode(person) 上面的示例非常简单,但是显示了2个要点 。 如果自定义类型的所有属性都是可编码的,则它是可编码的。 字符串,整数,双精度型, 数据和URL是内置的可编码类型,因此Person是可编码的。 让我们看一个反例。 结构资产{ let属性:Int […]

掌握CoreData(第16部分,多线程并发策略父级-子级用例2)

使用亲子策略放弃临时更改 在本部分中,我们将看到如何使用“父—子托管对象上下文”策略对UI临时更改核心数据对象。 首先下载启动项目。 注意:有关父级-子托管对象上下文策略,请参见第14和15部分。 当应用程序首次启动时,您将重定向到User屏幕,如图1所示。点击details按钮将执行两项任务。 首先,它将增加登录尝试(实体)计数器,然后将您重定向到“用户详细信息”屏幕,在该屏幕上将显示用户完整信息,用户可以在该屏幕中编辑信息,如图2所示。 图2是“用户详细信息”屏幕,用户可以在其中编辑其信息。 在背面,它移至上一个屏幕(用户屏幕),并放弃临时更改。 点击保存按钮将更新对核心数据的更改 项目结构 描述临时变更问题的项目结构如图3所示。 AppDelegate →负责创建核心数据堆栈。 ViewController→包含显示用户的逻辑,用户可以点击详细信息按钮以重定向到用户详细信息屏幕。 (用户画面) UserDetailViewController→包含用于显示来自Core Data的用户详细信息的逻辑以及用于在用户编辑信息后点击保存按钮时将更改保存到数据库的逻辑 TemporaryChanges.xcdatamodeld→包含两个实体 用户→包含属性firstname , lastName和id LoginAttempt→包含属性计数 问题 首次启动应用程序时,具有firstname和lastname用户(如果不存在)将保存到持久性存储中,并且其f firstname将显示在标签上,如图4所示。 现在,当您点击详细信息按钮时,它将执行两项任务 它将LoginAttempt count属性增加到+1,并通过调用save方法将其保存到持久性存储中 使用情节提要segue重定向到详细信息屏幕 现在点击“用户”屏幕上的“ 详细信息”按钮,它将重定向到用户详细信息屏幕,如图6所示。在此屏幕中,显示了用户详细信息。 用户可以通过单击保存按钮来更新其信息并将其保存到数据库中,也可以通过单击后退按钮放弃其临时更改。 更改用户详细信息,如图7所示,我们将firstname从Ali更改为Ali temp并且还更新了lastname 当用户在任何文本字段上键入内容时,它将更新NSMangedObject类型的User核心数据对象,该对象是控制器的实例属性。 现在,当用户完成firstname文本字段时,此更新也将反映到位于上下文中的user对象 众所周知, User对象是在主线程上下文中填充的,当我们执行临时更改时,它将在上下文中更新该对象,并且当我们点击后退按钮时,更新的值仍然存在于上下文中。 现在,点击后退按钮后,将出现用户屏幕。 我们知道,当我们点击详细信息按钮时,它将首先增加计数器并通过调用save方法来调用save方法,这还将把用户临时更改也推送到永久存储,并使用更新后的值重定向到User Detail屏幕。 由于受管对象上下文是单例对象save方法,因此会将临时更改推送到持久性存储 正如您在更新的屏幕中看到的那样,显示用户临时更改。 问题是,当用户执行后退按钮时,我们需要放弃更改。 我们可以通过三种方式做到这一点 使用父级—子级策略(此部分的封面) 撤消经理(下一部分) 手动跟踪更改(不会涵盖) 使用流程图了解问题 如您在图11中看到的,当应用程序首次启动时,用户信息将存储到持久性存储中。 当您点击详细信息按钮时,它将显示直接与UI交互的主要上下文中的用户详细信息 现在,用户在用于填充“用户详细信息”屏幕的直接coredata实体上编辑信息并更新其信息。 那时,由于User Detail使用核心数据用户对象(主要上下文中)填充其视图。 这种变化也将反映到上下文中。 […]

历史上最简单,最奇怪的CoreData简介

CoreData! 是! 没有! 等等…什么? 来自很多地方的很多意见。 什至是什么? iOS中的一些“数据库”东西,可以让您的应用存储东西,对吗? 但是,请等待,不要更改数据模型,否则必须进行迁移。 ?? 让我清楚一点:如果您没有从正确的地方学习,CoreData可能会使在线学习感到困惑。 这篇文章将像您从未见过的那样介绍CoreData:它是如此简单,以至于我的非编程性(但还真是太棒了)的妻子理解了它。 每当您开始使用CoreData时,都需要习惯一些术语和想法。 停。 请允许我为您提供更多乐趣,让它看起来不那么奇怪。 假设您是老板(是的!),您有几个员工。 这是特别忙碌的一天,但是突然有人突然冲进您的办公室,完全没有考虑到您只是在听泰勒·斯威夫特(Taylor Swift)的声音而现在却疯狂地试图隐藏它。 “达娜·斯库利(Dana Skully)刚把咖啡倒在我的全新Mac上!”,她在你的脸上吼叫着,以至于你实际上可以品尝到二手咖啡。 冻结。 眼前的不公正情绪激起了你的情绪。 我的意思是,咖啡从这个女人的脸上滴下来。 那个美丽的苹果电脑全都被破坏和浸泡。 你呢 a)当场射击达娜(最令人高兴) c)思考(大多数甘道夫) 令人震惊的事实是你还不能决定。 您需要一些上下文。 如果您要成为一名好经理,并且我们知道您想成为一名好经理 (您解雇了她,不是吗?),那么您需要了解有关情况的具体情况。 您需要有人回忆起发生了什么情况,以及在什么情况下是一名好经理的描述 (如果您解雇了她,只需责怪侠盗猎车手给您冲动的愤怒,所有的孩子都会这么做)。 我要去哪里? CoreData的工作原理与普通数据库略有不同,并且是一个很好的方法,但是考虑它的最佳方法是使用您创建的某种数据模型(足够简单,也许是新关系的颜色)。 但是,它将这些“联系”存储在上下文中,即托管上下文中 。 我对这种情况的看法是,其中的所有内容都有描述 ,例如涉及Dana Skully的不幸事件,我们稍后会再讲。 实际上,我们数据模型中的这些联系实际上是在您的应用程序中带有描述的,因此所有内容都可以正确存储。 最后一件事是,我忘了提到您是一家销售新Mac的商店的经理,所以每个人都还不错(您后悔解雇Dana)。 CoreData中的所有操作都是通过store完成的,好在这里存储您创建的内容。 应用程序关闭后,他们正等着您,从数据模型中加载,传递到商店并传递到可使用的托管对象上下文中 ! 如果您不感到困惑,那么恭喜您,您现在已经了解到有关CoreData的有用信息。 实际上,这就是我设法记住它的方式。 我做了一个故事。 不要相信那些“仅仅记住”事情的人,总是最好使用一个荒谬的故事,这是所有最优秀的人做事的方式。 那么最后,我们的Dana Skully发生了什么? 好吧,您奇怪地意识到:“达娜(Dana)已经走了……10…年”(乔伊·特里比安尼(Joey Tribianni)对于未成年人的参考)。 幽灵般的。 至少CoreData不会像这样开坏玩笑。

掌握CoreData(第15部分,多线程并发策略父级-子级用例1)

使用父子上下文解决了实际问题 托管对象上下文是用于处理托管对象的内存暂存器。我们使用多个托管对象上下文来执行两种类型的任务。 1)对于前面部分中讨论的长时间运行的任务。 在这一部分中,我们将在实际应用中执行此操作 2)在其他情况下,例如在对用户数据进行编辑时,将托管对象上下文视为一组更改即可很有用,如果应用程序不再需要它们,则可以将其丢弃。 使用子上下文使这成为可能。 在下一部分中,我们将介绍 在本教程中,您将通过使用GooglePlayViewerApp应用程序来使用多个托管对象上下文,并通过添加多个上下文以几种方式对其进行改进。 入门 该教程入门项目是一个Google Play查看器应用程序,用于演示。当应用程序首次启动时,您将重定向到登录屏幕,如图1所示。单击Export时,会将47472 google play应用程序数据加载到Core Data中。 点击“登录”按钮后,它将重定向到列表屏幕,其中将显示所有应用程序名称,如图2所示。 项目结构 在图3中显示了项目结构的屏幕截图 ViewController →负责登录屏幕任务。 它具有点击导出和登录按钮的操作方法。 点击登录按钮时,它将重定向到列表屏幕。 点击导出按钮,它将把csv文件中的数据加载到核心数据中,并将其保存到持久性存储中。 googleplaystore.csv→包含所有Google Play应用信息,总计47472 ,如图4所示。 GooglePlayListViewController →负责显示来自Google Play应用的列表。 它从核心数据中获取数据并在表格视图中显示。 AppDelegate→负责创建Core数据堆栈。 GooglePlayViewerApp.xcdatamodeld→包含Google play实体架构和配置 转到GooglePlayViewerApp.xcdatamodeld →选择Google Play实体,如图5所示,包含Google Play csv数据所需的所有属性 观察/问题 确保首先删除该应用程序。 运行该应用程序,将出现登录屏幕。 点击文本框并开始输入,它可以正常工作。 现在,点击导航栏左上方的导出按钮,立即再次开始键入,您将看到UI挂起。 导出操作需要几秒钟,并且会阻止UI响应诸如键入之类的交互事件。 怎么了 如图7所示,由于此应用程序仅使用一个托管对象上下文 ,该上下文将csv数据填充到主线程上的Core Data中。 当您点击“导出”按钮时,将发生以下情况 将包含47472数据的csv文件的所有内容加载到主线程的data变量中 获取在主线程上创建的托管对象上下文引用 在主上下文上创建了GooglePlay CoreData实体,并填充其属性 将数据推送到持久性存储 正如您在图7控制台日志中看到的那样,大约6秒的应用程序主线程将被此任务阻塞,您可以想象当应用程序冻结将近6秒时,用户的反应是什么 使用并发提高性能 […]