【问题标题】:Core data: executeFetchRequest vs performFetch核心数据:executeFetchRequest vs performFetch
【发布时间】:2012-09-20 16:06:17
【问题描述】:

我想要一份关于两者比较的完整列表。我知道的事情:

executeFetchRequest:

  • 消息已发送至 MOC
  • 返回一个托管对象数组
  • 目标:从持久存储中获取对象到 MOC
  • 与表视图:与表视图无关
  • 频率:经常循环使用,所以可以多次调用

performFetch:

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

如果我错了,请纠正我并附加列表。谢谢。

【问题讨论】:

    标签: objective-c core-data nsfetchedresultscontroller nsfetchrequest


    【解决方案1】:

    关于executeFetchRequest:

    消息发送到 MOC

    是的

    返回一个托管对象数组

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

    - (void)setResultType:(NSFetchRequestResultType)type
    

    其中NSFetchRequestResultType 可以是不同的类型。摘自 Apple 文档:

    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 初始化 过程。

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

    [fetchRequest setFetchBatchSize:20];
    

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

    频率:通常只有一次。除非 FRC 的 fetch 请求发生变化,否则不会 需要第二次调用 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]);
    }
    

    【讨论】:

    • 感谢您非常彻底的回答!不过我有一个问题:在什么情况下performFetch 会被运行时自动调用?我的例行程序是将“performFetch”放在我的 FRC getter/setter/或设置方法的末尾。这是一个好习惯吗?
    • @Philip007 我添加了一个编辑。希望能帮助到你。如果答案是好的,请将其标记为已回答并投票。干杯。
    • 非常感谢您提供使用 FRC 的例程。但是,我对此有些怀疑:你把performFetch放在viewDidLoad中,所以如果在viewDidLoad之后改变了FRC(这是正常的),performFetch就不会再被调用了。因此,您不会按预期看到新的 fetch 结果。 Apple doc 指示一个 3 步例程来使更改的 FRC 工作:删除缓存;然后改变FRC;然后拨打performFetch。请问您在日常工作中是如何处理这个问题的?
    • 另一个问题:总是在performFetch 之后调用reloadData 是否正确?看到这个帖子:stackoverflow.com/a/12659594/359248 你的reloadData 的例程是什么?
    【解决方案2】:

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

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

    【讨论】:

    • 您说“NSFetchedResultsController 使用 NSManagedObjectContext 执行提取”。这可能是 FRC 在内部的工作方式,而不是 FRC 的实际使用方式。例如,在使用 FRC 和表格视图的典型示例项目(如 Apple 的“CoreDataBooks”)中,您根本不接触上下文,更不用说将executeFetchRequest 发送到上下文。您只需将performFetch 发送到 FRC。如果我错了,请纠正我。
    • 其实内部并没有那么多。您必须使用获取请求初始化获取结果控制器。 NSFetchedResultsController 并没有不同的获取方式,它只是捕获获取结果的不同方式。
    • 确实FRC和MOC都使用了fetch request,这是显而易见的。但是它们的获取请求可以完全不同并且彼此不相关。由于 MOC 和 FRC 都可以实现相同的目的:进行 fetch,因此需要比较它们。对吗?
    • 再一次,NSFetchedResultsController 不进行获取。 NSManagedObjectContext 可以。 NSFetchedResultsController 是一种捕获获取结果的方法。
    • 你能解释一下“捕获”是什么意思吗?
    猜你喜欢
    • 1970-01-01
    • 2010-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-08
    相关资源
    最近更新 更多