coreData executeFetchRequest方法的Race Condition导致nil数据的问题



我遇到了一个竞赛条件,我不知道如何解决它。getPurchasedBookTitles和getBookEntryID位于使用NSOperationQueue的不同线程中,它们在调用fetchBook(这是不同类中的一个方法)时相互竞争。我把managedObjecContext(parent,child,root)和lock/unlock放在一起,以避免赛车的问题,但它似乎并不能解决根本问题。

问题是for循环中的book.bookTitle(所有图书中的book*book)有时会变为零,并导致应用程序崩溃或挂起。

提前感谢!

//在singleton类中,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;
}

核心数据不是线程安全的,您需要采取措施来处理它。我不确定是什么将bookTitle设置为零,但上面的代码有几个主要问题:

  1. "非线程安全"意味着您不能在多个线程上使用核心数据对象,除非您可以保证所有访问都是同步的。通过锁同步获取只涵盖了其中的一部分——您也不能在多个线程上同时使用获取的对象。您将在多个线程上使用相同的Book实例,这几乎可以保证会出现问题。通常的方法是为不同的线程/队列提供它们自己的托管对象上下文,并在进行更改时同步这些更改。

  2. 锁定会有所帮助,但前提是你确信自己已经找到了所有可能的方法。这很难做到正确,而且容易陷入僵局。这就是为什么核心数据包括专门为处理这种情况而设计的API。在此处查看performBlockperformBlockAndWait方法以获得帮助。使用这些而不是您自己的锁定方案。

最新更新