Core Data Freeze at fetch request(死锁)

Posted

技术标签:

【中文标题】Core Data Freeze at fetch request(死锁)【英文标题】:Core Data Freeze at fetch request ( Deadlock ) 【发布时间】:2013-10-24 20:44:53 【问题描述】:

我正在尝试实现获取请求,但它似乎陷入了僵局。

> 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 完成的。

我应该怎么做才能使它正确运行?

谢谢。

【问题讨论】:

【参考方案1】:

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

【讨论】:

谢谢,但我为此更新了我的代码:link,但仍处于死锁状态。代码下面有堆栈。 这是获取您使用上下文的唯一位置,还是您获取的任何对象?这似乎不太可能,因为您返回一个对象数组而不查看它们。仅将 fetch 放入 performBlock 是不够的。可能涉及上下文的所有内容都需要同步。 我发现了问题,我的 NSFetchedResultsController 没有使用带有 performBlock 的子上下文。谢谢汤姆哈灵顿。

以上是关于Core Data Freeze at fetch request(死锁)的主要内容,如果未能解决你的问题,请参考以下文章

Core Data Fetch 没有返回它应该返回的对象

iOS Core Data Fetch Request,如何使用

Core Data Fetch 在插入实体时保存关系(同时)

如何确保从上下文而不是缓存中获取 Core Data Fetched Property?

Core Data Fetch 在第二次使用谓词时返回 0 个结果

iOS NSArray, NSSet 与 Core Data Query (Fetch Request)