我知道有很多关于 NSManagedObjectContexts 和线程的线程,但我的问题似乎只特定于 iOS7。(或者至少在 OS6 中不可见)
我有一个使用 dispatch_queue_ 并运行多个线程从服务器获取数据并更新 UI 的应用程序。该应用程序在 iOS6 上运行良好,但在 iOS7 上似乎陷入死锁(互斥等待)。请参阅下面的堆栈跟踪 -
“等待”通常在执行获取请求并保存(不同的)上下文时以不同的方法发生。提交方法如下:
-(void)commit:(BOOL) shouldUndoIfError forMoc:(NSManagedObjectContext*)moc {
@try {
// shouldUndoIfError = NO;
// get the moc for this thread
NSManagedObjectContext *moc = [self safeManagedObjectContext];
NSThread *thread = [NSThread currentThread];
NSLog(@"got login");
if ([thread isMainThread] == NO) {
// only observe notifications other than the main thread
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(contextDidSave:)
name:NSManagedObjectContextDidSaveNotification
object:moc];
NSLog(@"not main thread");
}
NSError *error;
if (![moc save:&error]) {
// fail
NSLog(@"ERROR: SAVE OPERATION FAILED %@", error);
if(shouldUndoIfError) {
[moc undo];
}
}
if ([thread isMainThread] == NO) {
[[NSNotificationCenter defaultCenter] removeObserver:self
name:NSManagedObjectContextDidSaveNotification
object:moc];
}
}
@catch (NSException *exception) {
NSLog(@"Store commit - %@",exception);
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:@"name",@"store commit",@"exception", exception.description, nil];
[Flurry logEvent:@"MyException" withParameters:dictionary timed:YES];
}
@finally {
NSLog(@"Store saved");
}
}
我如何为每个线程创建新的上下文:
-(NSManagedObjectContext *)safeManagedObjectContext {
@try {
if(self.managedObjectContexts == nil){
NSMutableDictionary *_dict = [[NSMutableDictionary alloc]init];
self.managedObjectContexts = _dict;
[_dict release];
_dict = nil;
}
NSManagedObjectContext *moc = self.managedObjectContext;
NSThread *thread = [NSThread currentThread];
if ([thread isMainThread]) {
return moc;
}
// a key to cache the context for the given thread
NSString *threadKey = [NSString stringWithFormat:@"%p", thread];
if ( [self.managedObjectContexts valueForKey:threadKey] == nil) {
// create a context for this thread
NSManagedObjectContext *threadContext = [[[NSManagedObjectContext alloc] init] retain];
[threadContext setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy];
[threadContext setPersistentStoreCoordinator:[moc persistentStoreCoordinator]];
[threadContext setUndoManager:nil];
// cache the context for this thread
[self.managedObjectContexts setObject:threadContext forKey:threadKey];
NSLog(@"added a context to dictionary, length is %d",[self.managedObjectContexts count]);
}
return [self.managedObjectContexts objectForKey:threadKey];
}
@catch (NSException *exception) {
//
}
@finally {
//
}
}
到目前为止我所拥有的:
- 一名持久存储协调员。
- 每个新线程都有自己的托管对象上下文。
奇怪的是,相同的代码在 OS6 上运行良好,但在 OS7 上却不行。我仍在使用 xcode4.6.3 来编译代码。大多数代码都遵循这个原则,我运行一个线程,获取数据,提交它,然后发布一个通知。冻结/死锁可能是因为通知被发布并且我的 UI 元素在保存(&合并)被反映之前获取数据吗?还有什么我想念的吗?