1

我知道有很多关于 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 元素在保存(&合并)被反映之前获取数据吗?还有什么我想念的吗?

4

0 回答 0