Tag: 核心数据

NSFetchedResultsController不想被模拟

更具体地说,NSFetchedResultsController的Objective-C泛型不能很好地与Swift协议的relatedtype配合使用。 “测试工程”背后的思想是,不是针对具体类的接口编写代码,而是针对具有相同接口且具体类遵循的协议编写代码。 对于“真实”构建,使用真实对象。 为了进行测试,可以替换模拟对象或伪造对象,从而进行可靠的测试。 对于基于Core-Data的应用程序,这意味着创建一个我们要针对其进行编码的“ NSFetchedResultsControllerPrototol”。 NSFetchedResultsController实际上有一个使用的泛型类-它的原始定义为NSFetchedResultsController : NSObject where ResultType: NSFetchedRequestResult 。 这对我们来说是完美的,因为这样我们可以使用关联的类型,然后用模拟代替所出售的对象。 在写出该方法时,不会产生任何内联错误,并且在进行规划和开发的前提下,这是可行的。 但是,到了构建的时候,结果却截然不同: 编译期间的分段错误意味着编译器本身已崩溃。 不幸的是,使用泛型时经常发生这种情况,短期内别无选择,只能解决。 (但是在此之前,警告是一团糟,错误看上去像表情符号,说明它们如何使您感觉:’_’,等)。 iOS的核心功能仍然是本机Objective-C,即使以Swift表示,也要等到验证尽可能接近您的特定用例后,才能假设它会起作用。 仍然可以模拟核心数据,包括健壮的模拟; 随后的文章将对其进行探讨。 编辑:现在归档为 Open Radar 35110402 。

Swift 1中的核心数据:创建纯Swift NSFetchedResultsControllerDelegate

在Swift中使用Core Data的路径不像高速公路,而更像是一条依山傍水的危险小径。 但是,像许多Swift问题一样,问题不是新的危险,而是现有的不安全做法正在被揭示。 一种方法是简单地重新创建不安全的做法,例如使用隐式展开的可选方法。 另一种方法是将所有内容包装在“ guard”和“ if let”的多个级别中,以使控制流隐藏在不必要的分支中。 无论如何,Objective-C的假设在框架中构建得越深,在与众不同的Swift世界中就越难使用。 即使系统已试图弥合差距,例如将具有混合结果的Objective-C泛型添加到NSFetchedResultsController中,这也是正确的。 编译器崩溃后,需要另一种方法。 与许多Cocoa委托一样,在Swift中使用NSFetchedResultsController的可能性受到它所施加的要求的限制:委托必须是NSObject,其方法必须是Objective-C,并且回调不能是通用的。 目标是使NSFetchedResultsControllerDelegate适应隐藏其旧的Objective-C包。 这可以通过将NSFetchedResultsController包装在一个适配器类中来完成,该适配器类确实满足旧的要求,并在纯Swift中传递新的委托回调。 第一步是将委托重新创建为Swift协议: 这里的接口几乎与NSFetchedResultsControllerDelegate完全匹配(省去了无关的controller(_:sectionIndexTitleForSectionName) )。 该关联类型被命名为ResultType,并且由于它将是NSFetchedResultsController的ResultType,因此具有NSFetchRequestResult约束,但是我们并没有通过要求编译器将Objective-C桥接到Swift泛型而混淆了编译器。 注意,我们仍然使用NSFetchedResultsController:我们还没有准备好重构它。 现在的目标是适应代表。 因此,我们保留NSFetchedResultsController及其相关的“ NSFetchedRequestResult”和“ NSFetchedResultsChangeType”。 然后可以构建适配器: 即使不对泛型进行解码,也很难避免发生的事情:来自NSFetchedResultsController的委托消息被转换并传递给FetchedResultsControllerDelegate实例。 每个细节都需要考虑,但是要逐行考虑: 类声明和属性 像大多数泛型一样,类的声明可能不是直觉的。 大致可以分为三个部分: 1) class FetchedResultsControllerAdapter FetchedResultsControllerAdapter具有单个通用类型Delegate,它是我们之前创建的FetchedResultsControllerAdapterDelegate的实例。 AdapterDelegate在类型上必须是通用的,因为正如大多数Swift开发人员所了解的那样,由于它具有Self或关联的类型要求,因此只能用作通用约束。 在整个课程中,我们将其称为“委托”。 由于Delegate具有ResultType,因此我们也可以引用它,例如在Fetched Results Controller属性中: private(set) var fetchedRequestController : NSFetchedResultsController 这是确保NSFetchedResultsController和Delegate的ResultType匹配所必需的。 2) NSObject, NSFetchedResultsControllerDelegate FetchedResultsControllerAdapter是一个NSObject,它符合NSFetchedResultsControllerDelegate的要求。 3) where Delegate: AnyObject 对于内存管理存在此约束。 代表是保留周期的经典来源。 如果此对象强烈引用其委托,使其保持活动状态,并且如果该委托强烈引用该适配器(几乎可以肯定),则使其保持活动状态,则将永远不会释放这两个对象。 […]

掌握核心数据(第0部分)

#核心掌握数据 项目链接:https://github.com/aliakhtar49/Mastering-in-CoreData Twitter帐户:https://twitter.com/aliakhter49 Linkedin:https://www.linkedin.com/in/aliakhtar49 供讨论 https://ios-venturedive.slack.com/messages/CHE7CA7Q8/team/U67G7FYPM/? 内容正在审核中(进行中) 第1部分(简介) https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-1-introduction-7c5d667bfabd 第2部分(核心数据栈) https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-2-core-data-stack-ac447d3eb68c 第3部分(编码:核心数据中的CRUD) https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-3-coding-crud-in-core-data-b7a278436c3 第4部分(第4部分,面向核心数据对象的CRUD) https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-4-crud-in-core-data-object-oriented-style-a592439d7687 第5部分(核心数据中实体之间的关系) https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-5-relationship-between-entities-in-core-data-b8fea1b50efb 第6部分(核心数据CRUD操作中的实体之间的关系) https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-6-relationship-between-entities-in-core-data-crud-operation-87138fdf6fea 第7部分(核心数据关系删除规则) https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-7-core-data-relationships-delete-rules-4798c6c0e762 第8部分(核心数据中的验证) https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-8-validation-in-core-data-b38b8038e878 第9部分(NSFetchRequest) https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-9-nsfetchrequest-d9ad991355d9 第10部分(NSFetchRequest) https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-10-nsfetchrequest-a011684dd8f7 第11部分(多线程并发规则) https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-11-multithreading-concurrency-rules-70f1f221dbcd 第12部分(多线程并发问题) https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-12-multithreading-concurrency-problem-212a85f37930 第13部分(多线程并发策略通知) https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-13-multithreading-concurrency-strategy-notifications-63ef0f110293 第14部分(多线程并发策略父级-子上下文) https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-14-multithreading-concurrency-strategy-parent-child-context-305d986f1ac3 第15部分(父级多线程并发策略—儿童用例1) https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-15-multithreading-concurrency-strategy-parent-child-use-case-1-12a180a6fc34 第16部分多线程并发策略父级-子用例2 https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-16-multithreading-concurrency-strategy-parent-child-use-case-2-bf7dd7e5245a 第17部分多线程并发策略上下文UndoManager https://medium.com/@aliakhtar_16369/mastering-in-coredata-part-17-multithreading-concurrency-strategy-context-undomanager-d4a52138978a 第18部分使用核心数据的简单持久层架构 (进行中) 第18部分使用核心数据的高级持久层架构 (进行中) 第19部分:高级查询 (进行中) 第20部分核心数据中的错误 (进行中) 第21部分多个永久性商店 (进行中) 第22部分:多持久性存储协调器 (进行中) 第23部分:在App和Widget之间共享核心数据 (进行中) […]

在Swift中创建具有向后兼容性的核心数据栈

在2017年,我们生活在一个仍然存在非iOS 10设备的世界。 如果您的应用程序的目标版本早于iOS 10的iOS版本或macOS Sierra(10.12),您将无法利用Core Data的最新“堆栈创建”类NSPersistentContainer 。 所以,你可以做什么? 虽然NSPersistentContainer 确实旨在简化堆栈的创建过程,但最终还是要弄乱其中一些Core Data管道并不可怕。 创建核心数据栈的最终目标 创建核心数据堆栈的最终目标是获取NSManagedObjectContext的实例。 而已。 大多数依赖Core Data的应用最终都会发出获取请求来获取数据,或者连接其他类,例如NSFetchedResultsController 。 为了使这些事情起作用,您必须提供NSManagedObjectContext的实例。 NSManagedObjectContext是整个系统中的中心齿轮,它使其他齿轮转动。 所以。 底线:一旦有了NSManagedObjectContext实例,您就很NSManagedObjectContext 。 这就是创建核心数据堆栈最终为您提供的功能。 创建核心数据堆栈的3个步骤 可以大约3个步骤创建Core Data堆栈: 1)初始化NSManagedObjectModel的实例 这对应于您的.xcdatamodeld文件。 您需要浏览左侧的项目导航器,并找到.xcdatamodeld文件以记录此步骤的名称。 初始化NSManagedObjectModel //初始化NSManagedObjectModel let modelURL = Bundle.main.url(forResource:“ NameOfDataModel”,withExtension:“ momd”)保护let model = NSManagedObjectModel(contentsOf:modelURL!)else {fatalError(“未找到模型”)} //初始化NSManagedObjectModel 让modelURL = Bundle.main.url(forResource:“ NameOfDataModel”,withExtension:“ momd”) 警卫让模型= NSManagedObjectModel(contentsOf:modelURL!)else {fatalError(“找不到模型”)} 2)使用NSManagedObjectModel实例和NSPersistentStoreType初始化并配置NSPersistentStoreCoordinator实例 首先创建NSManagedObjectModel实例的原因是, 下一步取决于该实例。 NSPersistentStoreCoordinator将使用您的NSManagedObjectModel实例进行自我配置,并根据您要使用的NSPersistentStoreType准备创建正确的持久性存储类型。 在下面的代码示例中,我使用NSSQLiteStoreType创建一个SQLite持久存储。 […]

Swift 4.2初学者核心数据(CRUD)

核心数据是Apple在macOS和iOS操作系统中提供的对象图和持久性框架。 它是在Mac OS X 10.4 Tiger和带有iPhone SDK 3.0的iOS中引入的。 它允许将由关系实体-属性模型组织的数据序列化为XML,二进制或SQLite存储。 提取保存的数据的过程也非常容易。 它具有以下任务 准备实体的NSFetchRequest类型的请求(在本例中为User) 如果需要,使用谓词来过滤数据 从上下文中以[NSManagedObject]数组的形式获取结果 遍历数组以获取特定键的值 我们可以使用以下代码从Users实体中获取数据。 对于更新记录,我们必须使用与上述“检索数据”过程相同的谓词来检索/检索数据。 然后按照以下几步操作 使用实体谓词准备请求(在我们的示例中为User) 获取记录并使用键设置新值 并且Last Save上下文与创建数据相同。 对于删除记录,首先必须找到要通过fetchRequest删除的对象。 然后按照以下几个步骤删除记录 使用实体谓词准备请求(在我们的示例中为User) 获取记录以及我们要删除的记录 并进行context.delete(object)调用(参考下面的图片) 好吧,这还不足以支持核心数据,我们可以通过跟踪数据更改,添加谓词和数据库的复杂关系来完成许多复杂的事情。 随着您使用更多的核心数据,事情变得越来越复杂。 从这里下载完整的源代码

使用启动参数在Xcode中进行核心数据调试

Core Data是Apple的对象图管理和持久性框架,适用于iOS,macOS,watchOS和tvOS。 它已经存在很长时间了,因此是在应用程序中持久存储结构化数据的绝佳解决方案。 尽管Xcode中一些鲜为人知的功能可以为您提供很多帮助,但是Core Data Debugging可能会有些困难。 “让您快速入门的一种好方法是观看有关核心数据的WWDC会议。” 为了更好地了解您的应用程序正在保存的内容,直接打开SQL数据库非常有用。 检索数据库位置的最简单方法是启用SQL调试输出: -com.apple.CoreData.SQLDebug 1 您可以在Xcode的方案编辑器中设置此参数以启用SQL Core Data Debugging: 级别可以设置为4,以实现更详细的输出级别。 它将使您深入了解已执行的提取请求,访问的属性或保存的数据,并且通常是核心数据调试的绝佳工具。 启动应用程序时,它还会向您显示sqlite数据库文件的位置: CoreData:注释:在以下位置连接到sqlite数据库文件:/ Users / antoinevanderlee / Library / Developer / CoreSimulator / Devices / AB66C5B9-D1C1-45C4-9324-DB0E91FAB4F9 / data / Containers / Shared / AppGroup / C6934424-5E58-4164-8593- 3CC0D60D2BB5 / Coyote.sqlite“ 可以使用相同的SQL调试启动参数来发现繁琐的查询或在应用中触发很多请求的位置。 WWDC 2018的核心数据最佳实践会议更详细地介绍了此技术。 核心数据旨在在多线程环境中工作。 但是,并非Core Data框架下的每个对象都是线程安全的。 要在多线程环境中使用Core Data,请确保: 受管对象上下文绑定到初始化时与之关联的线程(队列) 从上下文中检索到的受管对象被绑定到上下文所绑定到的同一队列 […]

精通CoreData(第9部分,NSFetchRequest)

NSFetchRequest用于访问现有数据。 从Core Data获取对象是此框架最强大的功能之一。 它定义了从缓存(NSManagedObjectContext)或持久性存储中搜索/查询/检索数据的条件。 我们在较早的教程中使用了获取请求。 请参阅第4部分到第8部分,我们使用NSFetchRequest提取了对象。 说明 图1,获取请求将告诉托管对象上下文要获取的托管对象的实体; (可选)它指定其他方面,例如对对象属性必须具有的值的约束以及希望对象返回的顺序 。 提取请求是NSFetchRequest的实例。 它指定的实体由NSEntityDescription的实例表示。 任何约束均由NSPredicate对象表示,而排序由一个或多个NSSortDescriptor实例的数组表示。 它们分别类似于数据库SELECT语句的表名,WHERE子句和ORDER BY子句。 您可以通过向托管对象上下文发送消息来执行获取请求。 上下文返回一个数组,其中包含与请求匹配的对象(如果有) 入门 您可以在此处下载启动程序项目。 在第5部分中,我们讨论了验证,因此请完全注释掉“ User + CoreDataValidations.swift ”文件,因为它会产生问题,如果您遵循以前的教程,请先删除该应用程序。 获取NSManagedObject实例 转到xcdatamodel→点击User Entity→查看我们之前添加的属性 ,如图2所示。 从Core Data获取记录的过程具有以下任务,如图3所示。 从appdelegate单例对象引用persistentContainer 从persistentContainer创建/访问单例托管对象上下文 创建了一个提取请求,以仅过滤实体名称为User的 NSManagedObject。 除了返回的实体类型之外,此示例未对该数据添加任何要求 您将获取请求交给了托管对象上下文,以完成繁重的工作。 fetch(_ 🙂返回满足fetch请求指定条件的托管对象数组。 方法有两个可能的结果。 它要么返回带有零个或多个对象的NSManagedObject类型的NSArray对象,要么抛出一个错误,您从Core Data那里收到了一个错误,需要对其进行响应 筛选 NSPredicate对象用于获取请求以缩小/过滤返回的对象数。 例如,如果只希望具有firstName = ali的 User对象,则将谓词直接添加到NSFetchRequest 为了说明这个例子,让我们深入研究代码。 首先注释掉“ User + CoreDataValidations ”文件,以便不再进行任何验证。 在图4中,我们做了几件事 首先,我们添加了两个用户 […]

-[CFString版本]:消息发送到已释放实例— Core Data iOS

实现是直接的。 我有一个实体“ MyApp”,有一个属性“ newName”。 在viewWillAppear中,我只是创建实体,为属性分配值,进行保存,最后进行访存。 在保存之前一切都很好。 但是,当我打印获取的结果时,事情发生了。 崩溃…。 这就是我所得到的。 没有控制台日志,没有警告,没有谋杀武器。 最初的线索是EXC_BAD_ACCESS和EXC_1386,表明它的存在,是的,ZOMBIE。 僵尸是保留计数为0的对象仍然继续存在。 要确认它在产品->编辑方案->诊断中启用了僵尸,请为Zombie对象启用复选标记。 再次运行该应用程序,我得到了日志。 由于字符串僵尸对象而导致崩溃的原因。 是时候找到僵尸了。 为了更深入地研究,我们需要侦探“ xcode工具”的帮助。 打开xcode->开发人员工具->工具-> 选择僵尸 在方案中选择所需的模拟器和应用,然后点击红色的录制按钮。 景气,我们弹出这个僵尸, 查看分配历史记录,我发现在获取之后,访问属性“ newName”会导致该属性的内存释放, 但为什么 ? 动机是什么? 过渡到ARC发行说明 描述如何将代码从手动保留/发行转换为使用ARC。 developer.apple.com ARC对方法命名施加了约束: 您不能给访问器一个以new开头的名称。 解决案例后,将核心数据实体的属性从“ newName”重命名为“ updatedName”,解决了崩溃问题。 希望这对您有帮助。 任何帮助都可以通过pratheesh_db@hotmail.com与我联系。

让我们谈谈核心数据

核心数据之前 时间是晚上08:17,您上班迟到了。 前一天晚上真的很疯狂,您忘了给手机充电一整夜,您几乎无法起床。 您在地铁上都感到筋疲力尽,并向老板写了这么长的文字,解释并恳求她不要解雇您。 在按下绿色的大“发送”按钮之前,手机就死了。 您甚至开始惊慌失措,但是在背包中发现了一个移动电源,因此您立即开始为手机充电。 当它启动时,您输入消息应用程序,您长而宝贵的消息就消失了。 您无需写新信息,而是跑到办公室去和已经开始打包您的东西的老板见面。 她说:“简单的文字可以避免这种情况。” 我知道,我的描述确实很长很奇怪,但是就像在持久性数据之前那样。 不用担心那边突出显示的单词,我有一个解释: 持久性:“将数据保存到一个位置,在重新启动设备或应用程序后可以重新访问和检索数据,这对于任何想要长期存储数据并保持对用户可用的应用程序都是必要的 ” 我知道你在想什么 “这篇文章不是关于核心数据,不是关于持久性吗?” 没错,但是Core Data只是数据持久性选项的另一个常见选项。 最常见的四个是Default System , Property List , SQLite和Core Data 。 碰巧的是,Core Data现在正在主导其他所有选项。 但为什么? 为什么选择核心数据? 核心数据基本上是一个类似于UIKit的框架,但稍微复杂一些。 它用于管理模型或数据。 有一些内置功能将有所作为: 1.筛选 2.保存在磁盘上 3.撤消并重做数据 4.部分加载不同于UserDefaults 5.更改数据跟踪 Okey,听起来不错。 但是什么是核心数据? 什么是核心数据? 核心数据是苹果公司专有的持久性数据存储系统。 从根本上来说,这是一个可以在Github上找到的框架,但是有点复杂。 核心数据也不是数据库。 如果您熟悉MySQL,您可能会知道关系数据库以行,表和列的形式存储数据。 因此,请勿将核心数据与数据库混淆。 尽管SQLite数据库是iPhone上Core Data的默认持久存储,但Core Data不是关系数据库。 仅使用Core Data时,您可以将应用程序中的对象映射到数据库中的表记录,而无需任何SQL。 我应该如何学习核心数据? 正如我们自己的亚里士多德曾经说过的:“ 对于我们在做之前必须学习的东西,我们通过做来学习 。” […]

掌握CoreData(第5部分,核心数据中实体之间的关系)

出于本部分的目的,我们将扩展Todo应用程序。 最终应用将处理一对一和一对多关系。 我们将在后面的部分中讨论“ 多对多” 。 示例项目中有三个实体 1.用户→这将是主要实体,与Task和Passport实体具有关系 2.任务→这将包含用户的Todo任务,与用户具有多对一关系 3.护照→它将包含用户的护照信息,与用户具有一对一关系 这些都是到目前为止创建的所有实体,如图1,2和3所示。如果您不知道如何添加属性,请参阅第3部分。 创建关系时,您需要决定很多事情,这些选项在“ 数据模型”检查器选项卡的右侧,如图4所示。 您想与之建立关系的目标实体 →目标实体名称 基数 →关系是否是一对一,多对一 可选→关系可以为NULL / NOT NULL 瞬态 →内存使用率 限制 →如果是一对多,关系中是否存在最大或最小数量的对象? (下限不必为零) 方向 →大多数对象关系本质上是双向的 。 如果一个部门与一个部门中的员工有“到-许多关系”,则从员工到部门之间存在一对一的反向关系 。 推荐的方法是在两个方向上建模关系,并适当指定逆关系。 如果进行更改,Core Data将使用此信息来确保对象图的一致性 删除规则→关系的删除规则指定如果尝试删除源对象 ,应在目标实体上发生什么。 拒绝 →如果关系目的地(员工)上至少有一个对象,请不要删除源对象(部门)。 Nullify →删除对象之间的关系,但不要删除任何一个对象。 级联 →删除源时,删除关系目标处的对象。 无操作 →对关系目标处的对象不执行任何操作 。 “操作”规则可能没有用,因为如果使用该规则,则有可能使对象图处于不一致状态(员工与已删除部门有关系)。 一对一关系(用户→护照) 现在,我们创建用户与护照的关系。 用户可以拥有与其关联的一本护照。 转到用户实体→在“关系”上单击+,然后单击→添加关系详细信息,如图5所示。 对于逆关系,我们还需要在另一侧创建关系 转到“护照实体”→在“关系”上单击+,然后单击→添加关系详细信息,如图6所示。 现在我们需要确定删除规则。 如果删除了用户,则无需保留用户护照怎么办,因此我们将用户→护照删除规则设置为级联,如图7所示,这意味着在删除用户1时,核心数据会自动删除与用户1相关联的所有护照。 其次,我们选择“ 数据模型”检查器的“类型”点击上的“ […]