如何在不通知 NSFetchedResultsController 的情况下更新 NSManagedObject 或 NSManagedObjectContext

Posted

技术标签:

【中文标题】如何在不通知 NSFetchedResultsController 的情况下更新 NSManagedObject 或 NSManagedObjectContext【英文标题】:How to update a NSManagedObject or NSManagedObjectContext without notifying a NSFetchedResultsController 【发布时间】:2013-12-27 14:25:41 【问题描述】:

我有一个托管对象上下文,其中有几个 NSFetchedResultsControllers 在整个应用程序中监听不同的实体,大部分情况下都可以正常工作。

我不知道如何解决以下情况:当用户单击实体的相应表格视图单元格中的按钮时,我正在设置实体上的关系。这当前会导致实体发生变化,FRC 会告诉 tableview 重绘整个单元格,将按钮呈现在其默认的控制状态。

有没有办法在不被我的 FRC 注意到的情况下更改实体?

与暂时禁用整个 FRC 相比,我希望能够仅对特定更新(由我自己控制,例如设置或删除关系)产生这种影响,以免失去其他更新的功能这可能同时发生。

谢谢!

【问题讨论】:

我正在考虑使用布尔值来实现您的目标。该值将允许您控制NSFetchedResultsController 委托将如何响应更新.. 问题是单元格被“立即”重绘,取消了 UI 的正常过渡动画,对吗? 【参考方案1】:

可以使用“原始访问器”方法

[object setPrimitiveValue:... forKey:...]

因为这不会导致任何更改通知。但这可能有不想要的 副作用。

更好的解决方案可能是将按钮状态存储在(瞬态) 对象的属性,以便在单元格时可以正确恢复它 已重绘。

【讨论】:

这是个好主意,但由于我在更新后立即保存上下文,所以无论如何我都会收到更改通知。有没有办法解决这个问题? @akelagercrantz:我不知道。替代建议呢? 它可以工作,但在我的场景中非常麻烦,因为按钮状态是临时的,并且会在一段时间后改变(点击后显示反馈 - 用户将产品添加到购物车)。 @akelagercrantz:但它可能发生在单元格被重绘的任何时候,由于滚动。 确实,但我可以忍受。如果用户滚动并再次返回,按钮的反馈可能已经被注意到并且不再相关。【参考方案2】:

也许我不明白您的问题,但如果您只想禁用 NSFetchedResultsController 委托并因此禁用渲染,正如我评论的那样,您可以为此使用 bool 值。

这里是基本的想法。在这里,stopAutomaticTrackingOfChanges 将是公共的,而 beganUpdates 可以在类扩展中维护。

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller

    if (!self.stopAutomaticTrackingOfChanges) 
        [self.tableView beginUpdates];
        self.beganUpdates = YES;
    


- (void)controller:(NSFetchedResultsController *)controller
  didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
           atIndex:(NSUInteger)sectionIndex
     forChangeType:(NSFetchedResultsChangeType)type

    if (!self.stopAutomaticTrackingOfChanges)
    
        switch(type)
        
            // your code here
        
    
    

- (void)controller:(NSFetchedResultsController *)controller
   didChangeObject:(id)anObject
       atIndexPath:(NSIndexPath *)indexPath
     forChangeType:(NSFetchedResultsChangeType)type
      newIndexPath:(NSIndexPath *)newIndexPath

    if (!self.stopAutomaticTrackingOfChanges)
    
        switch(type)
        
            // your code here
        
    


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller

    if (self.beganUpdates) [self.tableView endUpdates];

这个想法取自斯坦福课程的CoreDataTableViewController.h/.m 代码(参考http://www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2011-fall)。

【讨论】:

@MartinR 我没有从问题中理解它。我将等待OP的详细信息。目前尚不清楚 OP 是否会这样做。感谢您的评论。无论如何,如果问题不正确,我将删除我的答案。谢谢。 @MartinR 在这种情况下,结果集的顺序不会改变。事实上,视图根本不会发生任何变化。这可能有效,但是我会错过同时发生的数据集的任何其他更改。这可能永远不会发生,但它可以。我宁愿在特定更改而不是特定时间段内禁用它。 @flexaddicted:看来我评论中的假设是错误的,所以我删除了它。

以上是关于如何在不通知 NSFetchedResultsController 的情况下更新 NSManagedObject 或 NSManagedObjectContext的主要内容,如果未能解决你的问题,请参考以下文章

收到 FCM 通知时如何在不点击通知的情况下打开(启动)应用程序

如何在不唤醒 Android 屏幕的情况下发送通知

如何在不显示通知的情况下 startForeground()?

在 Android 11 上,如何在不实际点击通知的情况下从通知更新启动 Activity

如何在不点击通知的情况下从通知中获取数据(firebase 云消息传递和本机反应)

如何在不与 MainActivity 交互的情况下从通知中打开片段页面?