获取例程中的死锁

时间:2012-03-27 12:23:33

标签: objective-c ios core-data grand-central-dispatch synchronized

我使用application =)

时遇到了我的第一个GCD和第一个核心数据

两个视图访问相同的数据(由单个DAO处理)。

如果我等待当前视图完成加载其内容,则更改视图时不会出现问题。

但是:如果我在一个控制器尝试从我的模型中获取数据时更改视图(其基于tabbased),则新控制器尝试相同并且线程“碰撞”并且我的应用程序冻结。

冻结发生在我DAO的这行代码中:

    NSArray *results = [managedObjectContext executeFetchRequest:fetch error:&error];    

reloadAllMonth()访问我的DAO的提取例程

我如何在第一个控制器中加载数据:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
                [self reloadAllMonth];

                dispatch_async(dispatch_get_main_queue(), ^(void) {                        
                    [self.allMonthTable reloadData];    
                });

在第二个viewcontroller中我做的第一件事是更新我的DAO,这当然使用(在其他人之下)我之前调用的相同的获取例程:

    [self.dataHandler updateData];
到目前为止,我尝试了两种方法:

首先使用c-semaphore:

-(NSArray *)fetchAllMonthExpenses{  
    //@return: array of all expenses in month (day & month type)


    NSNumber *monthNumber = [self getMonthNumber:[NSDate date]];
        NSEntityDescription *exp = [NSEntityDescription entityForName:@"Expense" inManagedObjectContext:managedObjectContext];
    NSFetchRequest *fetch = [[NSFetchRequest alloc]init];
    [fetch setEntity:exp];
    [fetch setPredicate:[NSPredicate predicateWithFormat:@"month == %@",monthNumber]];
    NSError *error = nil;
    sem_wait(&isLoading);
    NSArray *results = [self.managedObjectContext executeFetchRequest:fetch error:&error];  
    sem_post(&isLoading);
    return results;

}

第二次使用synchronized指令

-(NSArray *)fetchAllMonthExpenses{  
    //@return: array of all expenses in month (day & month type)


    NSNumber *monthNumber = [self getMonthNumber:[NSDate date]];
        NSEntityDescription *exp = [NSEntityDescription entityForName:@"Expense" inManagedObjectContext:managedObjectContext];
    NSFetchRequest *fetch = [[NSFetchRequest alloc]init];
    [fetch setEntity:exp];
    [fetch setPredicate:[NSPredicate predicateWithFormat:@"month == %@",monthNumber]];
    NSError *error = nil;
    @synchronized(self.class){
        NSArray *results = [self.managedObjectContext executeFetchRequest:fetch error:&error];  
        return results;
    }    
}
遗憾的是,这两种方法都不起作用,应用程序冻结了我所做的一切。

所以我的问题是:我做错了什么(正如我第一次提到的那样使用线程),我错过了什么,我应该在哪里看?

这让我忙了2天,我似乎无法绕过它:/

1 个答案:

答案 0 :(得分:4)

NSManagedObjectContext及其中的所有NSManagedObjects都不是线程安全的。

无论您使用什么线程来创建上下文,都需要是 only 线程,您可以在其中执行与该上下文相关的任何。即使只是从其中一个托管对象读取值,也必须在该线程上 而不是在任何其他线程上完成。

如果你需要两个处理相同数据库的线程,你有两个选择:

  • 使用dispatch_sync()暂时跳转到另一个线程以对托管对象和/或上下文执行所有读/写操作

或者:

  • 在同一个数据库的另一个线程中创建第二个NSManagedObjectContext,并保持对这两个上下文的任何更改同步。

第一个选项更容易,但可能会消除线程的许多好处。第二个选项更难,但可以完成,并且有一个相当不错的API可以保持不同线程上的两个上下文同步。

查看核心数据编程指南以获取更多详细信息。