多次调用NSManagedObjectContextDidSaveNotification

时间:2015-10-16 20:12:13

标签: ios core-data ios9

您好我有一个FriendsViewController,我在其中显示从coreData获取的朋友记录。我有另一个View Controller AddFriendViewController由FriendsViewController提供,以添加一个新的朋友,它将Context保存在其中。我正在收听FriendsViewController中共享MOC上的更改通知。

 [[NSNotificationCenter defaultCenter]
 addObserverForName:NSManagedObjectContextDidSaveNotification
 object:appdelegate.context queue:nil 
 usingBlock:^(NSNotification * _Nonnull note) {
                    NSLog(@"Re-Fetch Whole Friends Array from core data and Sort it with UILocalizedIndexedCollation and  reloadData into table");
                }];

在AddFriendsViewController中只需创建一个朋友对象,我就

Friend *friend= [NSEntityDescription 
                insertNewObjectForEntityForName:@"Friend" 
                inManagedObjectContext:appdelegate.context];
friend.name=nameTextfield.text;
[appdelegate.context save:&error];
[self.navigationController popViewControllerAnimated:YES];

现在,当我从AddFriendViewController执行上下文保存时,FriendsViewController中的上述块被触发几次而不是一次,因为重新获取会导致更多处理来自核心数据的整个数据。我不能使用Fetched Results Controller,因为我使用UILocalizedIndexedCollat​​ion将我的数组排序到部分。所以我的问题是为什么它被召唤两次,有时甚至三次?或者有其他替代方案吗?

3 个答案:

答案 0 :(得分:1)

只有您知道希望通知观察者何时处于活动状态。

然而,两种常见的范例是:

如果您希望在视图控制器的生命周期内随时收到通知,请在viewDidLoad中注册观察者并删除dealloc中的观察者。

如果您希望在视图处于有效状态时收到通知,请在viewWillAppear中注册观察者并在viewWillDisappear中删除。

修改

  

我使用此语句删除所有条目[[NSNotificationCenter   defaultCenter] removeObserver:自];它仍然显示相同   行为。然后我使用了addObserver:selector:name:object:方法   哪个有效。但为什么另一个没被删除? - 阿萨杜拉·阿里

那是因为你添加了一个基于块的观察者,它返回一个观察者对象。您删除它返回给您的对象。您真的应该阅读您使用的每种方法的文档。

如果使用block-observer方法,则添加/删除将如下所示。

id observer = [[NSNotificationCenter defaultCenter]
    addObserverForName:SomeNotification
                object:objectBeingObserved
                 queue:nil
            usingBlock:^(NSNotification *note) {
    // Do something
}];

[[NSNotificationCenter defaultCenter] removeObserver:observer];

如果使用selector-observer方法,则需要删除为add调用提供的观察者。

[[NSNotificationCenter defaultCenter]
    addObserver:someObject
       selector:@selector(notificationHandler:)
           name:SomeNotification
         object:objectBeingObserved];

[[NSNotificationCenter defaultCenter]
    removeObserver:someObject
              name:SomeNotification
            object:objectBeingObserved];

答案 1 :(得分:1)

首先,我强烈建议使用NSFetchedResultsController而不是建立自己的观察者。

其次,听起来好像你要多次添加观察者。您应该将其添加到-viewDidLoad中,然后将其移除-dealloc

同样,NSFetchedResultsController是更好的解决方案。你将获得更好的表现并避免像你现在所做的那样重新获得。

答案 2 :(得分:0)

你必须摆脱观察者(正如其他人已在此处所述)。最简单的方法是使用“一次性观察者”,在激活时自动移除。在您的示例代码中,这将是:

id __block observer;
observer = [[NSNotificationCenter defaultCenter]
            addObserverForName:NSManagedObjectContextDidSaveNotification
            object:[PubStore sharedStore].managedObjectContext queue:nil            
            usingBlock:^(NSNotification * _Nonnull notification) {
                [[NSNotificationCenter defaultCenter] removeObserver:observer];
                 NSLog(@"Re-Fetch Whole Friends Array from core data and Sort it with UILocalizedIndexedCollation and  reloadData into table");
            }];

请注意,您必须将观察者存储在__block变量中,以便能够在触发观察者时执行的块内使用它。