精通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中,我们做了几件事

  1. 首先,我们添加了两个用户
  2. 通过调用save方法将对象保存到持久性存储中

现在,我们需要过滤具有firstName =“ ali ”的User对象,它仅返回一个用户 ,如图5所示。

排序

NSSortDescriptor对象用于基于所有对象共有的属性对NSFetchRequest获取的对象集合进行排序/排序。 例如,如果要按firstName 升序对所有User对象进行排序,则可以将NSSortDescriptor实例直接添加到NSFetchRequest中。

为了说明这个例子,让我们深入研究代码。 首先删除该应用程序。 如您在图6中看到的,我们创建了三个具有不同的firstNamesecondName的 用户

如您在图7中看到的,我们做了很多事情

  1. 首先,我们创建了两个排序描述符,并且在考虑了secondName之后,将User的 firstName属性赋予了最高优先级
  2. 在控制台中打印,结果如图7的控制台所示进行排序

优化

在本节中,我们将看看NSFetchRequest提供了哪些功能来改善读取时间响应和内存消耗

搜索哪个持久性商店

在第2部分“ 核心数据堆栈”部分中,我们在“ 持久性存储”标题下说:

我们可以在每个堆栈上创建多个持久性存储

可以使用NSFetchRequest上的setAffectedStores 方法将获取请求修改为搜索特定商店。

创建对象时,可以使用NSManagedObjectContext上的assignObject:toPersisentStore:方法将实体分配到特定商店。 如您在图8中看到的,我们将用户,护照和任务实体分配给持久性存储区1

提取请求从持久性存储中提取了数据。 大多数应用程序只有一个持久性存储,但是有些应用程序可以具有多个持久性存储。 NSFetchRequest具有受影响的 Stores属性,该属性采用持久性存储数组,当您执行此提取请求时,它将仅在这些持久性存储上搜索。 如您在图8中所看到的,我们告诉提取请求仅查看持久性存储区一

  [请求setAffectedStores:[NSArray arrayWithObjects:firstStore,secondStore,thirdStore,nil]]; 

此假设未经测试

  1. 当您的应用程序具有多个持久性存储并且您未指定受影响的存储属性时,它将从所有持久性存储中查找
  2. 如果指定此属性,它将仅查找这些存储

如图8所示,您可以在仅包含User实体的商店中进行查询,这肯定会提高获取结果的性能

提取请求的结果类型

您可以设置获取请求的结果。 我们知道NSFetchRequest总是返回Array,但是数组类型结果类型决定。 NSFetchrequest当前支持四种结果类型,如下所列

  1. managedObjectResultType(默认)
  2. dictionaryResultType。 (返回字典数组)
  3. countResultType。 (只返回计数)
  4. managedObjectIDResultType(仅返回objectIds)

如您在图10中看到的,我们使用了ManagedObjectResultType,为此我们执行了许多任务

  1. 首先,我们创建了一个数组类型为User的获取请求
  2. 其次,我们使用“ managedObjectResultType ”定义结果类型,这是默认类型,我们从fetchrequest中期望它( 确保步骤1和步骤2应该一致,否则应用程序将崩溃 )。在大多数情况下,我们需要这种类型,这就是为什么是默认的
  3. 您可以看到已打印的User对象,如图9所示, 用户整个对象已打印在控制台上

如图10所示,我们使用了dictionaryResultType,为此我们执行了许多任务

  1. 首先,我们创建了一个数组类型为NSDictionary的获取请求
  2. 其次,我们使用“ dictionaryResultType ”定义结果类型,这是fetchrequest所期望的( 确保步骤1和步骤2应该一致,否则应用程序将崩溃 )。
  3. 打印的用户详细信息,使用其属性作为字典中的 ,如图10所示

如图11所示,我们使用了countResultType,为此我们执行了许多任务

  1. 首先,我们创建了一个数组类型为NSNumber的获取请求
  2. 其次,我们使用“ countResultType ”定义结果类型,这是我们从fetchrequest期望的结果( 确保步骤1和步骤2应该一致,否则应用程序将崩溃 )。
  3. Printed User用户在数据库中计数,如图10所示。您可以看到有时我们只需要总计数,而不是将整个对象加载到内存中,因此我们可以使用它来确实减少内存消耗

如图12所示,我们使用了ManagedObjectIDResultType,为此我们执行了许多任务

  1. 首先,我们创建了一个数组类型为NSManagedObjectID的获取请求
  2. 其次,我们使用“ managedObjectIDResultType ”定义结果类型,这是我们从fetchrequest期望的结果( 确保步骤1和步骤2应该一致,否则应用程序将崩溃 )。
  3. 打印的用户对象ID,对于上下文中的每个记录都是唯一的。 您可能会想到的问题是什么是NSManagedObjectID ,我们将在进行多个managedObjectContext或线程化部分时对此进行研究。 当我们只有一个NSManagedObjectContext时,它不是很有帮助。 目前,如果您对此一无所知,可以,但是您应该考虑的是,我们也可以通过将其resultType更改为NSManagedObjectID来在获取请求中返回NSMangedObjectId 。 当我们需要在两个上下文之间传输数据时,它肯定会优化性能。

摘要

在第9部分中,我们通过编码和图表深入研究了NSFetchRequest,还探讨了如何使用其隐藏功能来改善内存和时间。

接下来是什么?

本教程越来越大,所以我决定将其分为其他部分。 因此,在第10部分中,我们将介绍NSFetchRequest支持的其他功能和优化技术。

有用的链接

https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/FetchingObjects.html

https://developer.apple.com/documentation/coredata/nsfetchrequest

https://stackoverflow.com/questions/6913156/which-persistent-store-is-used-by-default-in-core-data-in-iphone

https://developer.apple.com/library/archive/documentation/DataManagement/Devpedia-CoreData/fetchRequest.html#//apple_ref/doc/uid/TP40010398-CH26-SW1
https://developer.apple.com/documentation/coredata/nsfetchrequest/1506518-affectedstores