2013-08-21 17 views
0

我遇到了一个竞争条件,我不知道如何解决它。 getPurchasedBookTitles和getBookEntryIDs在使用NSOperationQueue的不同线程中,它们互相竞争调用fetchBooks(这是不同类中的方法)。我把managedObjecContext(父,孩子,根)放在锁/解锁的位置,以避免赛车的问题,但似乎并没有解决根本问题。coreData executeFetchRequest方法的竞争条件导致无数据的问题

问题是for-loop中的book.bookTitle(在allBooks中的book * book)会在某些时候变为零,并导致应用程序崩溃或挂起。

在此先感谢!

//在一个单独的类,dispatch_once

- (NSArray *)getPurchasedBookTitles 
{ 
    NSMutableArray *bookTitles = [[NSMutableArray alloc] init]; 

    NSArray *allBooks = [[CoreDataManager sharedInstance] fetchBooks]; 

    for (Book *book in allBooks) 
    { 
     if (book.bookTitle != nil && book.is_owned != nil) 
      if (![bookTitles containsObject:book.bookTitle] && [[book is_owned] boolValue] == YES) 
       [bookTitles addObject:book.bookTitle]; 
    } 

    return bookTitles; 
} 

- (NSArray *)getBookEntryIDs 
{  
    NSMutableArray *bookTitles = [[NSMutableArray alloc] init]; 

    NSArray *allBooks = [[CoreDataManager sharedInstance] fetchBooks]; 

    for (Book *book in allBooks) 
    { 
     if (book.bookTitle != nil) 
      if (![bookTitles containsObject:book.bookTitle]) 
       [bookTitles addObject:book.bookTitle]; 
    } 

    return bookTitles; 
} 

//在类coreDataManager // managedObjectContextChild,managedObjectContext,writerManagedObjectContext的声明,并在细节的appDelegate和coreDataManager类实例化。

- (NSArray *)fetchBooks 
{   
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"bookTitle" ascending:YES]; 
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil]; 
    NSFetchRequest *request = [[NSFetchRequest alloc] init]; 
    [request setEntity:bookEntity]; 
    [request setPredicate:nil]; 
    [request setSortDescriptors:sortDescriptors]; 

    [managedObjectContextChild lock]; 
    [managedObjectContext lock]; 
    [writerManagedObjectContext lock]; 

    NSError *error = NULL; 

    NSArray *results = [managedObjectContextChild executeFetchRequest:request error:&error]; 

    if (error != NULL) 
     NSLog(@"Error fetching - %@", error); 

    [writerManagedObjectContext unlock]; 
    [managedObjectContext unlock]; 
    [managedObjectContextChild unlock]; 

    return results; 
} 

回答

2

核心数据不是线程安全的,您需要采取措施来解决这个问题。我不知道发生了什么设置bookTitle为零,但也有几个重大问题与上面的代码:

  1. “不是线程安全”意味着你不能使用在所有对核心数据对象多线程除非你能保证所有的访问都是同步的。通过锁来同步读取仅涵盖其中的一部分 - 您无法同时在多个线程上使用获取的对象。您将在多个线程上使用相同的Book实例,这几乎可以确保问题。通常的做法是为不同的线程/队列提供自己的托管对象上下文,并在变更完成时同步更改。

  2. 锁定可以帮助,但只有当你确定你已经击中每一种可能性。很难正确并容易发生死锁。这就是为什么Core Data包含专门用于处理这种情况的API。请在此处查看performBlockperformBlockAndWait方法以获取帮助。使用这些而不是您自己的锁定方案。

+0

感谢您的帮助,但对象Book分别在不同的线程上被提取以供不同的方法使用...... getPurchasedBookTitles和getBookEntryIDs在不同的线程上运行。 – Jerry

+1

是的,这正是问题所在。您从不同线程上的相同受管对象上下文获取相同的Core Data实例,然后在不同线程上使用同一个实例。事实上,你使用不同的线程没有适当的预防措施是整个问题。 –

+0

这是第一个使用managedObjectContext锁定的好主意吗? – Jerry