Ios 多次调用NSManagedObjectContextDidSaveNotification

Ios 多次调用NSManagedObjectContextDidSaveNotification,ios,core-data,ios9,Ios,Core Data,Ios9,嗨,我有一个FriendsViewController,在那里我可以显示从coreData获取的朋友记录。我有另一个视图控制器AddFriendViewController,它由FriendsViewController提供,用于添加新朋友,并将上下文保存在其中。我正在FriendsViewController中收听共享MOC上的更改通知 [[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectConte

嗨,我有一个FriendsViewController,在那里我可以显示从coreData获取的朋友记录。我有另一个视图控制器AddFriendViewController,它由FriendsViewController提供,用于添加新朋友,并将上下文保存在其中。我正在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 *friend= [NSEntityDescription 
                insertNewObjectForEntityForName:@"Friend" 
                inManagedObjectContext:appdelegate.context];
friend.name=nameTextfield.text;
[appdelegate.context save:&error];
[self.navigationController popViewControllerAnimated:YES];

现在,当我从AddFriendViewController对上下文执行保存时,FriendsViewController中的上述块被触发几次,而不是一次,这会导致更多处理,因为从核心数据重新获取整个数据。我无法使用“获取结果”控制器,因为我正在使用UILocalizedIndexedCollation将数组排序到节中。所以我的问题是,为什么它被称为两次,有时甚至三次?或者有其他选择吗?

只有您知道何时需要激活通知观察者

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

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

如果希望在视图处于活动状态时随时收到通知,请在
视图中注册观察者将出现
,并在
视图中删除观察者将消失

编辑


我使用此语句删除所有条目[[NSNotificationCenter] defaultCenter]removeObserver:self];而且还是一样的 行为。然后我使用addObserver:selector:name:object:method 这起作用了。但是为什么另一个没有被移除呢阿萨杜拉·阿里

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

如果使用块观察者方法,则添加/删除将如下所示

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

[[NSNotificationCenter defaultCenter] removeObserver:observer];
如果使用选择器观察者方法,则需要删除为add调用提供的观察者

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

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

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

第二,听起来您多次添加观察者。您应该在
-viewDidLoad
中添加它,并在
-dealoc
中删除它


同样,NSFetchedResultsController是一个更好的解决方案。您将获得更好的性能,并避免像现在这样重新蚀刻。

您必须摆脱观察者(正如其他人已经在这里说明的那样)。最简单的方法是使用一个“一次性观察者”,它在激活时会自动移除。在您的示例代码中,这类似于:

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");
            }];

请注意,必须将观察者存储在
\u块
变量中,才能在触发观察者时执行的块内使用它

您是否碰巧使用了多个托管对象上下文,它们之间有父/子关系?我已经发现我必须删除此观察者我正在didLoad中添加此观察者,但不知道从何处删除它?另外,我在堆栈中的该视图控制器后面有一个视图控制器,因此每次我返回并再次推送到该视图时,它都会添加另一个观察者。我希望使用NSFetchedResultsController,就像我在其他TableViewController或ViewController中使用它一样。但是我不能在这里使用它,因为我必须支持不同语言的名称(在我的例子中是中文、英文)才能用SectionIndexTitle进行排序。我已经尽力了,但最终还是这样做了。如果您能建议使用FRC进行中文、英文排序的其他方法,我们将不胜感激。Ref:我注意到使用此方法添加的观察者addObserverForName:object:queue:usingBlock:未在dealloc方法中删除。block观察者有一些问题。我不建议使用它。还有其他问题吗。因为jodyI在下面澄清了我面对的问题,我注意到使用此方法添加的ObserverForName:object:queue:usingBlock:在dealloc方法中未被删除。我使用此语句删除所有条目[[NSNotificationCenter defaultCenter]removeObserver:self];它仍然表现出同样的行为。然后我使用了addObserver:selector:name:object:method,这很有效。但是为什么另一个没有被删除呢?是的,这一个总结了。谢谢