在更新时跟踪 NSManagedObject 属性并立即更新视图

Posted

技术标签:

【中文标题】在更新时跟踪 NSManagedObject 属性并立即更新视图【英文标题】:Track NSManagedObject property when it was updated and immediately update view 【发布时间】:2014-09-05 15:43:37 【问题描述】:

我有一个问题,我如何才能听到我的数据模型的变化。

我有带有属性进度的 NSManagedObject 电子邮件。因此,当应用程序发送电子邮件时,我每次都会更新属性进度。

我想听数据模型,如果改变了更新我的视图。

我补充说:

 for (SAPEmail *email in _emails)
    
        [self addObserver:email forKeyPath:@"progress" options:NSKeyValueObservingOptionNew context:NULL];
    


- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context

    if ([keyPath isEqualToString:@"progress"])
    
        SAPEmail *email = object;

        NSLog(@">>>>>>>>>>> progress: %@", email.progress);
    

但似乎对我不起作用。

我也使用 MagicalRecord。

我也尝试观察上下文

[[NSNotificationCenter defaultCenter] 
      addObserver:self 
         selector:@selector(handleDataModelChange:) 
             name:NSManagedObjectContextObjectsDidChangeNotification 
           object:myManagedObjectContext];

但是当我调试我的数据模型时,我的数据模型已经更新了 10 次(因为我更新了从 0 到 9 的进度),但是在所有更新完成后,handleDataModelChange 只调用了一次。但是每次更新数据模型以更新进度视图时,我都需要更新所有 10 个。

如果我用这个,再来一个

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(managedObjectContextDidSave:) name:NSManagedObjectContextDidSaveNotification object:nil]; 

然后例如尝试刷新数据:

- (void)managedObjectContextDidSave:(NSNotification *)notification

    NSLog(@">>>>>>>>>+++++");

    _emails = [SAPCoreDataEmailHelper emailsWithStatus:EmailStatusInProgress];

    [_theTableView reloadData];


+ (NSArray *)emailsWithStatus:(EmailStatus)status

    NSPredicate *prediacte = [NSPredicate predicateWithFormat:@"status == %d", status];
    NSArray *emails = [SAPEmail MR_findAllWithPredicate:prediacte];
    return emails;

我可以看到 NSLog 是如何工作的,但是我的应用程序被冻结了。

【问题讨论】:

【参考方案1】:

更好的是,将获取的对象保存在 NSFetchedResultsController 中。通过这种方式,您可以自动监控非常具体的实体,而无需过多详细地观察每个属性。

您的控制器是否实现了NSFetchedResultsControllerDelegate 方法。这真的很简单,使用 Core Data 查看 Xcode 模板(例如 Master-Detail Project,查看“Core Data”)。

【讨论】:

【参考方案2】:

您设置的观察者不正确,请使用以下代码设置您的观察。

 for (SAPEmail *email in _emails)
 
     [email addObserver:self forKeyPath:@"progress" options:NSKeyValueObservingOptionNew context:NULL];
 

我还建议setting the context parameter 正确触发 KVO 观察。


更新

当您想观察 Core Data 的变化时,您有一些选择。我认为您没有掌握有多种方法可以做到这一点。第一种方法是监视单个对象上单个属性的更改。这就是 KVO 方法。如果你想监听特定上下文的保存事件,那么你需要使用 NSNotificationCenter 方法。当您对多个上下文进行更改时,您需要混合使用这两者。也就是说,如果您在上下文 A 中观察对象的属性,并且在上下文 B 中对该对象/属性进行了更改,则需要在 NSManagedObjectContextDidSaveNotification 上设置 NSNotificationCenter 观察处理程序,以将上下文 B 中的新更改合并到上下文 A。从那里,当上下文合并完成时,然后触发您对上下文 A 中的属性/对象的 KVO 观察。

在您的情况下,在您的 managedOjbectContextDidSave: 方法中,您需要调用 -mergeChangesFromContextDidSaveNotification: 合并上下文之间的更改。我还建议使用多个上下文,并且不要在 SAPCoreDataEmailHelper 类中保存单个上下文。当您进入多线程场景时,您会遇到单上下文和多线程的随机崩溃。

【讨论】:

感谢您每次都回答您帮助我)我有单身人士为我发送电子邮件,在这里我使用神奇的导入来设置所有属性以及进度。在视图控制器的另一个对象中,我想观察我所有的电子邮件,当我初始化这个视图控制器时,我创建了 SAPEmail MR_findAllWithPredicate。但我认为当核心数据发生变化时,我在视图控制器中使用的电子邮件并不知道它。因为更改发生在上下文中,而不是我通过 MR_findAllWithPredicate 获得的对象。对吗? 还是观察不到

以上是关于在更新时跟踪 NSManagedObject 属性并立即更新视图的主要内容,如果未能解决你的问题,请参考以下文章

跟踪 NSManagedObject 的属性变化

核心数据:访问 NSManagedObject 属性时应用程序崩溃

消失的 NSManagedObject

willSave 或 validateForUpdate 中的 NSManagedObject 动态属性更新

自动更新 NSManagedObject 属性修改时间戳

在 NSManagedObject 编辑上更新 SwiftUI 视图