核心数据在获取请求时冻结(死锁)

时间:2013-10-24 20:44:53

标签: objective-c core-data deadlock

我正在尝试实现获取请求,但它似乎处于死锁状态。

> Thread 1, Queue : com.apple.main-thread
> #0    0x38329fa8 in __psynch_mutexwait ()
> #1    0x38390f0e in _pthread_mutex_lock ()
> #2    0x2d3aaad0 in -[_PFLock lock] ()
> #3    0x2d3bbba4 in -[NSPersistentStoreCoordinator executeRequest:withContext:error:] ()
> #4    0x2d3ba7e6 in -[NSManagedObjectContext executeFetchRequest:error:] ()
> #5    0x2d448bb6 in -[NSManagedObjectContext(_NestedContextSupport) _parentObjectsForFetchRequest:inContext:error:] ()
> #6    0x2d44932e in __82-[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:]_block_invoke ()
> #7    0x2d43ec82 in _perform ()
> #8    0x2d449030 in -[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:] ()
> #9    0x2d3ba7e6 in -[NSManagedObjectContext executeFetchRequest:error:] ()
> #10   0x000e4c90 in +[PhotoDAO getNotSentPhotos:] at /Users/vitrinysolutions/Documents/Workspace XCode/Novo
> SmileClick/SmileClick/SmileClick/DAOs/PhotoDAO.m:236
> #11   0x0009f210 in -[EventManager loadQueue:] at /Users/vitrinysolutions/Documents/Workspace XCode/Novo
> SmileClick/SmileClick/SmileClick/Util/EventManager.m:59
> #12   0x00095fb0 in -[EventMainViewController viewDidAppear:] at /Users/vitrinysolutions/Documents/Workspace XCode/Novo
> SmileClick/SmileClick/SmileClick/ViewControllers/EventMainViewController.m:60
> #13   0x2fdf03da in -[UIViewController _setViewAppearState:isAnimating:] ()
> #14   0x2fdf085c in -[UIViewController _endAppearanceTransition:] ()
> #15   0x2fe9ced2 in -[UINavigationController navigationTransitionView:didEndTransition:fromView:toView:] ()
> #16   0x2ff6831c in __49-[UINavigationController _startCustomTransition:]_block_invoke ()
> #17   0x2feecc22 in -[_UIViewControllerTransitionContext completeTransition:] ()
> #18   0x2ffacff6 in __53-[_UINavigationParallaxTransition animateTransition:]_block_invoke105 ()
> #19   0x2fe0dfe8 in -[UIViewAnimationBlockDelegate _didEndBlockAnimation:finished:context:] ()
> #20   0x2fe0dc36 in -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] ()
> #21   0x2fe0db4e in -[UIViewAnimationState animationDidStop:finished:] ()
> #22   0x2fa65d08 in CA::Layer::run_animation_callbacks(void*) ()
> #23   0x3824ed66 in _dispatch_client_callout ()
> #24   0x382557c0 in _dispatch_main_queue_callback_4CF$VARIANT$mp ()
> #25   0x2d62f820 in __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ ()
> #26   0x2d62e0f4 in __CFRunLoopRun ()
> #27   0x2d598ce6 in CFRunLoopRunSpecific ()
> #28   0x2d598aca in CFRunLoopRunInMode ()
> #29   0x32286282 in GSEventRunModal ()
> #30   0x2fe3aa40 in UIApplicationMain ()
> #31   0x000aeedc in main at /Users/vitrinysolutions/Documents/Workspace XCode/Novo SmileClick/SmileClick/SmileClick/main.m:16

我有这些方法来制作我的孩子语境:

static __strong NSManagedObjectContext *context;

+(NSManagedObjectContext*) context {
    if (context == nil) {
        context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
        [context setParentContext: [((AppDelegate*)[[UIApplication sharedApplication] delegate]) managedObjectContext]];
    }
    return context;
}

+ (void)save:(NSManagedObjectContext *)context {
    [context performBlockAndWait:^{

        NSError *error;

        if (![context save:&error]) {

            NSLog(@"Child Context Error: %@", error);

        } else {
            NSManagedObjectContext *parentContext = [((AppDelegate*)[[UIApplication sharedApplication] delegate]) managedObjectContext];

            if (![parentContext save:&error]) {
                NSLog(@"Parent Context Error: %@", error);
            }

        }

    }];
}

我的获取方法:

+(NSArray *) getNotSentPhotos: (Event *) oEvent {

    NSManagedObjectContext *context = [self context];

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Photo" inManagedObjectContext:context];
    [fetchRequest setEntity:entity];

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(event == %@) AND (server_status == %@)", oEvent, SERVER_STATUS_PENDENTE];
    [fetchRequest setPredicate:predicate];

    NSError *error = nil;
    NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];

    return fetchedObjects;

}

我的子上下文是NSPrivateQueueConcurrencyType,所有保存都是使用performBlock完成的。

我想做些什么才能让它正常运行?

谢谢。

2 个答案:

答案 0 :(得分:3)

你提到“所有保存都是使用performBlock完成的,这很好但不够。 NSManagedObjectContext对于几乎所有事情都不是线程安全的。您的获取请求不在performBlock的上下文中,但确实需要。此外,您使用上下文的其他所有内容,以及使用您获取的托管对象时。像这样的死锁是线程问题的典型症状,performBlock旨在帮助避免。

答案 1 :(得分:0)

我发现了问题,我的NSFetchedResultsController未使用performBlock的子上下文。

谢谢Tom Harrington。