带有线程(调度队列)的ManagedObjectContexts在iOS7上陷入死锁

时间:2013-10-17 17:20:57

标签: xcode core-data mutex grand-central-dispatch nsmanagedobjectcontext

我知道有很多关于NSManagedObjectContexts和线程的线程,但我的问题似乎只针对iOS7。 (或者至少在OS6中不可见)

我有一个使用dispatch_queue_的应用程序,并运行多个线程从服务器获取数据并更新UI。该应用程序在iOS6上工作正常但在iOS7上它似乎陷入死锁(互斥等待)。请参阅下面的堆栈跟踪 -

enter image description here

“等待”通常在执行获取请求和保存(不同)上下文时以不同的方式发生。提交方法如下:

-(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元素在反映保存(& merge)之前获取数据?我还缺少什么?

0 个答案:

没有答案