我一直在使用支持多线程的Core Data应用程序时遇到了问题,因此我认为我应该仔细检查一下我的操作和方式。请告诉我以下内容是否可行。
我有一个单例DataManager
类来处理Core Data相关的事务。它有一个属性managedObjectContext
,为每个线程返回不同的MOC。因此,给定NSMutableDictionary *_threadContextDict
(将字符串线程名称映射到上下文)和NSMutableDictionary *_threadDict
(将字符串线程名称映射到线程),它看起来像这样:
-(NSManagedObjectContext *)managedObjectContext
{
if ([NSThread currentThread] == [NSThread mainThread])
{
MyAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
return delegate.managedObjectContext; //MOC created in delegate code on main thread
}
else
{
NSString *thisThread = [[NSThread currentThread] description];
{
if ([_threadContextDict objectForKey:thisThread] != nil)
{
return [_threadContextDict objectForKey:thisThread];
}
else
{
NSManagedObjectContext *context = [[NSManagedObjectContext alloc]init];
MyAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
[context setPersistentStoreCoordinator:delegate.persistentStoreCoordinator];
[_threadContextDict setObject:context forKey:thisThread];
[_threadDict setObject:[NSThread currentThread] forKey:thisThread];
//merge changes notifications
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:@selector(mergeChanges:)
name:NSManagedObjectContextDidSaveNotification object:context];
return context;
}
}
}
}
在
mergeChanges
方法中,我将来自传入通知的更改合并到除生成通知的上下文之外的所有上下文中。代码如下:-(void)mergeChanges:(NSNotification *)notification
{
MyAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = delegate.managedObjectContext;
[context performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification)
withObject:notification waitUntilDone:YES];
for (NSString *element in [_threadContextDict allKeys])
{
if (![element isEqualToString:[[NSThread currentThread] description]])
{
NSThread *thread = [_threadDict objectForKey:element];
NSManagedObjectContext *threadContext = [_threadContextDict objectForKey:element];
[threadContext performSelector:@selector(mergeChangesFromContextDidSaveNotification)
onThread:thread withObject:notification waitUntilDone:YES];
}
}
}
每当我保存 MOC 上的更改时,都会调用共享的 DataManager 上的 saveContext 方法,该方法调用从上述属性获取的上下文上的 save 方法:
-(void)saveContext
{
NSManagedObjectContext *context = self.managedObjectContext;
NSError *err = nil;
[context save:&err];
//report error if necessary, etc.
}
根据我对核心数据多线程规则的理解,我觉得这应该可以工作。我为每个线程使用单独的上下文,但所有线程都使用相同的持久存储。但是,当我使用它时,即使我的线程不在同一对象(
NSManagedObject
子类)上工作,我仍然会遇到许多合并冲突。我只是从网络下载数据、解析结果并将它们保存到Core Data中。我做错了什么吗?我尝试过使用NSLock
实例锁定某些内容,但那样我只会遇到卡顿问题。更新/解决方案:通过添加一件简单的事情,我成功地使其工作。当完成一个线程/MOC对时,我添加了一种方法来从字典中删除它。在每次调用
dispatch_async
中的每个块的末尾,我调用[self removeThread]
,这会从字典中删除当前线程及其MOC。我也只合并对主线程MOC的更改。实际上,这意味着每次在后台线程上工作时,我都会获得一个全新的MOC。我还通过向
userInfoDict
添加数字来区分线程,而不是调用description
。该数字是通过我的类上的只读属性获得的,每次调用它时返回一个更高的数字。