核心数据:executeFetchRequest vs performFetch

时间:2012-09-28 18:44:44

标签: objective-c core-data nsfetchedresultscontroller nsfetchrequest

我想要一份关于两者之间比较的详细清单。我所知道的事情:

executeFetchRequest

  • 发送给MOC的消息
  • 返回托管对象数组
  • 目标:将持久存储中的对象提取到MOC
  • 使用表格视图:与表格视图无关
  • 频率:经常在循环中使用,因此可以被多次调用

performFetch

  • 发送给FRC的消息
  • 调用它之后,使用fetchedObjects返回一个托管对象数组
  • 使用表视图:FRC专门用于保持托管对象和表视图行同步,并使用performFetch初始化该进程。
  • 频率:通常只有一次。除非FRC的获取请求发生更改,否则无需再次调用performFetch

如果我错了,请纠正我并附上清单。谢谢。

2 个答案:

答案 0 :(得分:16)

关于executeFetchRequest:

  

发送给MOC的消息

  

返回一个托管对象数组

是的,但您也可以更改要检索的结果类型。在NSFetchRequest中,您可以使用以下内容设置不同的结果类型:

- (void)setResultType:(NSFetchRequestResultType)type

其中NSFetchRequestResultType可以是不同类型。取自Apple doc:

enum {
   NSManagedObjectResultType        = 0x00,
   NSManagedObjectIDResultType      = 0x01,
   NSDictionaryResultType           = 0x02
   NSCountResultType                = 0x04
};
typedef NSUInteger NSFetchRequestResultType; 
  

目标:将持久存储中的对象提取到MOC

是,创建NSFetchRequest并执行请求,与在SQL中创建SELECT语句相同。如果你也使用NSPredicate它与使用SELECT-WHERE语句相同。

  

使用表视图:与表视图无关

是的,但是对于检索到的数据,您可以填充表格

  

频率:经常在循环中使用,所以可以多次调用

这取决于你想要达到的目标。它可能在一个循环内或没有。在循环中执行请求可能会对性能产生影响,但我不会担心这一点。在引擎盖下,Core Data维护着一种缓存机制。每次执行请求时,如果数据不在缓存中,Core Data会在您的商店(例如sql文件)上执行往返,并使用它检索到的对象填充缓存。如果执行相同的查询,由于缓存机制,往返将不会再次执行。无论如何,您可以避免在运行循环中执行请求,只需将该请求移出循环。

关于performFetch:

  

发送给FRC的消息

  

调用它之后,使用fetchedObjects返回托管数组   对象

是的,但如果要填充表格中的特定单元格,也可以使用[_fetchedResultsController objectAtIndexPath:indexPath];检索对象。

我建议您在NSFetchedResultsController

上阅读一个很好的教程
  

使用表视图:FRC专门用于保持托管对象和   表视图行同步,并使用performFetch初始化它   过程

是的,NSFetchedResultsControllerNSManagedObjectContext结合使用。此外,它还可以延迟加载数据。假设您检索了1000个元素,并且希望在UITableView中显示它们。设置NSFetchRequest的请求,如:

[fetchRequest setFetchBatchSize:20];

并将其与NSFetchedResultsController的实例一起使用,它允许首先加载20个元素。然后滚动时,会加载其他20个元素,依此类推。如果没有NSFetchedResultsController,您必须手动实现此行为。请参阅我提供的教程以获取更多信息。

  

频率:通常只有一次。除非FRC的获取请求发生变化,否则不行   需要再次调用performFetch

这取决于你想要达到的目标。大多数时候你可以打电话一次。

希望有所帮助。

修改

您必须明确致电performFetch。我喜欢在我的头文件(.h)中为NSFetchedResultsController创建一个属性,如

@property (nonatomic, strong, readonly) NSFetchedResultsController* fetchedResultsController;

并在您的实现文件(.m)中合成它,如

@synthesize fetchedResultsController = _fetchedResultsController;

然后始终在.m文件中覆盖getter以创建它的新实例:

- (NSFetchedResultsController*)fetchedResultsController
{
    // it already exists, so return it
    if(_fetchedResultsController) return _fetchedResultsController;

    // else create it and return

    _fetchedResultsController = // alloc-init here with complete setup

   return _fetchedResultsController;
}

完成后,在您的课程中(例如在viewDidLoad方法中),请使用

NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {

    // Handle the error appropriately.
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
}

答案 1 :(得分:4)

您正在比较错误的元素。 NSFetchedResultsController使用NSManagedObjectContext执行提取,并在正确配置下监视托管对象上下文中的更改以验证它正在监视的提取属性的状态,但实际提取是由上下文。在这两种情况下,NSManagedObjectContext执行提取。不同之处在于,直接使用NSManagedObjectContext,您将获得NSArray类型的对象(实际运行时类与使用[NSArray array]获得的数组不同),而NSFetchedResultsController具有不同的类型目的(拥有结果集合并监视对其获取请求的记录和实体的更改)。换句话说,NSFetchedResultsController使用上下文工作,但它的工作方式不同于简单的对象集合。

一个观察结果:你不应该在循环中使用executeFetchRequest,尤其是“多次”调用它。每次获取都有其性能成本。您可以调用executeFetchRequest一次,然后循环检查结果。