我有一个单身名称CoreDataManager
,在其中注册了mergeContextChangesForNotification
:
+ (id) sharedManager{
static CoreDataManager *mSharedManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
mSharedManager = [[CoreDataManager alloc] init];
});
return mSharedManager;
}
- (id)init
{
self = [super init];
if (self) {
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(mergeContextChangesForNotification:)
name:NSManagedObjectContextDidSaveNotification
object:nil];
});
}
return self;
}
收到通知后:
- (void)mergeContextChangesForNotification:(NSNotification *)notification {
[shareContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:)
withObject:notification
waitUntilDone:YES];
}
我在这里有两个问题:
performSelectorOnMainThread
吗?因为this answer表示从不。我应该将其更改为GCD并使用dispatch_get_main_queue
?? mergeContextChangesForNotification
中init
的注册是否是确保通知始终在主线程中注册的良好做法?我从this answer 答案 0 :(得分:8)
使用iOS 5 / OS X 10.7中引入的托管对象并发类型是首选
使用performBlock
方法确保执行Core Data操作
在正确的线程上(更确切地说:在正确的队列中)。
因此,您将使用
创建共享上下文shareContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
并将来自其他上下文的更改与
合并- (void)mergeContextChangesForNotification:(NSNotification *)notification {
[shareContext performBlock:^{
[shareContext mergeChangesFromContextDidSaveNotification:notification];
}];
}
另请注意(如NSManagedObjectContext
文档中所述)
建议仅从已知上下文注册保存通知。
注册时object:nil
,您可能会收到意外通知,因为系统框架在内部使用Core Data。
所以你应该只注册你创建的上下文。 或者,您可以检查 从具有相同持久性存储协调器的上下文发送通知:
- (void)mergeContextChangesForNotification:(NSNotification *)notification {
NSManagedObjectContext *otherContext = [notification object];
if (otherContext != shareContext &&
[otherContext persistentStoreCoordinator] == [shareContext persistentStoreCoordinator]) {
[shareContext performBlock:^{
[shareContext mergeChangesFromContextDidSaveNotification:notification];
}];
}
}
最后,总是在发布的线程上调用通知方法。 通知已注册的线程无关紧要。因此 不需要将注册分派给主线程。
答案 1 :(得分:1)
检查TopSongs示例应用程序,请记住它们并不完美,但大部分时间可能用于参考。他们正在同步mergeChangesFromContextDidSaveNotification
调用只在主线程上进行,但是以更优雅的方式进行:
// This method will be called on a secondary thread. Forward to the main thread for safe handling of UIKit objects.
- (void)importerDidSave:(NSNotification *)saveNotification {
if ([NSThread isMainThread]) {
[self.managedObjectContext mergeChangesFromContextDidSaveNotification:saveNotification];
[self.songsViewController fetch];
} else {
[self performSelectorOnMainThread:@selector(importerDidSave:) withObject:saveNotification waitUntilDone:NO];
}
}
对于初始化,-init
将在调用的同一个线程+sharedManager
上调用。
此外,由于您链接的第二个答案在文档方面的信息量不大,因此我要留下指向文档的Concurrency with Core Data部分的链接。