【问题标题】:Can't receive NSManagedObjectContextDidSaveNotification while save context in a NSOperation subclass在 NSOperation 子类中保存上下文时无法接收 NSManagedObjectContextDidSaveNotification
【发布时间】:2011-10-25 02:12:13
【问题描述】:

我正在使用MagicalRecord 帮助核心数据操作。

我有一个名为OfflineRetrieveOperationNSOperation 子类。它从服务器检索消息并保存。 代码是这样的:

NSManagedObjectContext *context = [NSManagedObjectContext contextForCurrentThread];
Message *existMessage = [Message MessageWithMessageID:messageID inManagedObjectContext:context];

if (!existMessage) {
  Message *message = [Message insertMessageWithProperties:properties inManagedObjectContext:context];
}
[context save];

通知接收器是这样初始化的:

- (id)init
{
  self = [super init];

  if (self != nil) {
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(contextDidSave:) 
                                                 name:NSManagedObjectContextDidSaveNotification 
                                               object:[NSManagedObjectContext defaultContext]];
    [self setContext:[NSManagedObjectContext context]];
  }
  return self;
}

日志:

-[NSManagedObjectContext(MagicalRecord) saveWithErrorHandler:](0x5906a0) Saving Context
-[NSManagedObjectContext(MagicalRecord) mergeChangesFromNotification:](0x37eab0) Merging changes to *** DEFAULT *** context *** on Main Thread ***

一切似乎都很好,只是我根本收不到NSManagedObjectContextDidSaveNotification,所以我不知道我已经完成了检索。

【问题讨论】:

    标签: core-data notifications nsoperation


    【解决方案1】:

    您的OfflineRetrieveOperation 可能正在创建自己的NSManagedObjectContext。当您保存该上下文时,它将触发NSManagedObjectContextDidSaveNotification。但是,您有一个观察者,它将收听NSNotification 正在由[NSManagedObjectContext defaultContext] 广播。

    将您的观察者更改为使用来自您的OfflineRetrieveOperation 内部NSManagedObjectContext 而不是[NSManagedObjectContext defaultContext] 的通知,它应该开始接收它们。

    【讨论】:

    • 谢谢你,马库斯。我尝试在不同的线程中进行各种操作,然后将更改合并到 [NSManagedObjectContext defaultContext]。
    • 广播通知的是操作的NSManagedObjectContext。您需要将您的 addNotification 的 object: 设置为广播者(或 nil)以接收通知。我建议阅读 NSNotificationNSNotificationCenter 的工作原理。
    • 由于有不同类型的操作可能会改变数据,通知接收者只关心defaultContext会很方便。我想我可以这样做:[[OfflineRetrieveOperation context] save]; [[NSManagedObjectContext defaultContext] 保存];第二次保存会触发 NSManagedObjectContextDidSaveNotification 并且通知接收器将收到此消息。如果 [notification userInfo] 没有内容,则使用 NSFetchedResultsController 执行 Fetch 并获取最新的数据。
    • 没有。只有操作的上下文会触发通知,因为它是唯一有变化的上下文。时期。您必须侦听操作上下文或 nil 以使其正常工作。
    • 我试过了。第二次保存确实触发了 NSManagedObjectContextDidSaveNotification,并且 [notification userInfo] 为空:{ insert = "{(\n)}";更新 = "{(\n)}"; }
    【解决方案2】:

    所以,我猜您可能希望在将 defaultContext 中的对象保存在后台上下文中时更新它们。当您使用辅助方法创建新上下文时,MagicalRecord 实际上已经为您处理了这种情况。也就是说,当你做这样的事情时:

    NSManagedObjectContext *backgroundOperationContext = 
              [NSManagedObjectContext contextThatNotifiesDefaultContextOnMainThread];
    

    上下文方法已经设置了必要的通知,告诉默认上下文在后台保存时合并更改。您需要做的就是在后台操作中保持上下文处于活动状态,并在准备好持久化数据时调用 save。

    在幕后,上下文方法正是在 Marcus 建议的时候做的,也就是在通知中心添加一个通知:

    [NSNotificationCenter defaultCenter] addObserver:[NSManagedObjectContext defaultContext]        
                                            selector:... 
                                                name:NSManagedObjectContextDidSaveNotification 
                                              object:backgroundOperationContext]
    

    这不完全是代码,但这几乎就是它的作用。

    底线,不用担心自己观察和合并从背景上下文到默认上下文的更改,MagicalRecord 会为您处理。

    【讨论】:

    • +1 MagicalRecord 的创建者当然最有可能知道。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多