为什么在回滚后NSManagedObjectContextObjectsDidChangeNotification与已删除的对象一起调用了两次?

时间:2015-12-23 00:23:55

标签: ios objective-c macos core-data rollback

我正在使用NSManagedObjectContextObjectsDidChangeNotification,我有一个问题,在插入一个对象然后调用rollback以便删除它之后,带有已删除对象的更改通知被调用两次。这个意外的通知引起了我追溯到这个问题的复杂性。我已编辑Apple's Earthquakes example来演示此问题。编辑是:

- (void)viewDidLoad {
    [super viewDidLoad];

    [self reloadTableView:self];

    [[NSNotificationCenter defaultCenter]
     addObserver:self
     selector:@selector(contextObjectsDidChangeNotification:)
     name:NSManagedObjectContextObjectsDidChangeNotification
     object:self.managedObjectContext];

    AAPLQuake* quake = (AAPLQuake *)[NSEntityDescription insertNewObjectForEntityForName:@"Quake" inManagedObjectContext:self.managedObjectContext];

    NSLog(@"Why is deleted notified twice?");
    [self.managedObjectContext rollback];
}

-(void)contextObjectsDidChangeNotification:(NSNotification*)notify{
    NSLog(@"contextObjectsDidChangeNotification:");
    NSDictionary* userInfo = notify.userInfo;
    NSSet* inserted = userInfo[NSInsertedObjectsKey];
    if(inserted){
        NSLog(@"\tinserted %ld", inserted.count);
    }
    NSSet* deleted = userInfo[NSDeletedObjectsKey];
    if(deleted){
        NSLog(@"\tdeleted %ld", deleted.count);
    }
}

运行此结果会产生以下输出:

2015-12-23 00:15:20.086 Earthquakes[7631:5431685] Why is deleted called twice?
2015-12-23 00:15:20.086 Earthquakes[7631:5431685] contextObjectsDidChangeNotification:
2015-12-23 00:15:20.086 Earthquakes[7631:5431685]   inserted 1
2015-12-23 00:15:20.086 Earthquakes[7631:5431685] contextObjectsDidChangeNotification:
2015-12-23 00:15:20.087 Earthquakes[7631:5431685]   deleted 1
2015-12-23 00:15:20.087 Earthquakes[7631:5431685] contextObjectsDidChangeNotification:
2015-12-23 00:15:20.087 Earthquakes[7631:5431685]   deleted 1

可用的示例项目here

有谁知道为什么会这样?我在OS X 10.11.2和iOS 9.2上都遇到过它。

2 个答案:

答案 0 :(得分:2)

我看到了同样的行为,我不知道它为什么会发生。但是,看起来您可以通过查看托管对象的hasChanges属性来区分第一个调用与第二个调用。在第一次通话时,hasChanges为YES,在第二次通话时,它为NO。这应该至少足以避免自己两次处理删除。

对象的deleted属性发生了同样的变化,因此最好同时检查两者。

答案 1 :(得分:1)

rollback调用processPendingChanges,第一个通知是对象被删除的结果,并且似乎具有所需的所有其他值(inserted和{{1都是真的。)

第二个通知是在deleted的实施中第二次调用processPendingChanges的结果。请注意,这次它甚至没有标记为rollback

起初,我认为可能是由于删除传播,但即使deleted设置为NO,也会发生第二次通知。

以下跟踪只是propagatesDeletesAtEndOfEvent方法(我删除了除rollback以外的所有方法调用以保持简短 - 我还删除了对retain / release的调用。)

可能有充分的理由对NSManagedObjectContext进行第二次调用,因为那里发生了相当多的工作(参见本文末尾)。

如果我不得不猜测,我会说回滚的实现存在一个错误,其中删除的对象没有从第二个通知的数据中删除。

我建议采取两种行动方案。首先,使用apple提交错误报告。其次,当您处理对象更改事件时,请检查已删除通知集中对象的processPendingChanges属性,并忽略任何未标记为deleted的对象。

这是跟踪......

deleted