ios - coreData executeFetchRequest 方法的竞争条件导致 nil 数据的问题

标签 ios multithreading core-data fetch race-condition

我遇到了竞争条件,但我不知道如何解决它。 getPurchasedBookTitles 和 getBookEntryIDs 在使用 NSOperationQueue 的不同线程中,它们相互竞争调用 fetchBooks(这是不同类中的方法)。我把 managedObjecContext(parent, child, root) 和 lock/unlock 放在一起来避免 racing 的问题,但是好像并没有解决根本问题。

问题是 for 循环中的 book.bookTitle(Book *book in allBooks)有时会变成 nil 并导致应用程序崩溃或挂起。

提前致谢!

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

最佳答案

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

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

  2. 锁定会有所帮助,但前提是您确定已找到所有可能性。很难做到正确并且容易陷入僵局。这就是为什么 Core Data 包含一个专门为处理这种情况而设计的 API。在此处查看 performBlockperformBlockAndWait 方法以获得帮助。使用它们而不是您自己的锁定方案。

关于ios - coreData executeFetchRequest 方法的竞争条件导致 nil 数据的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18361895/

相关文章:

multithreading - (Tomcat) 网络服务 : OutOfMemoryError: unable to create new native thread

ios - 从 coreData 加载图像时崩溃

c++ - 使用 C++ 编写的算法实时处理数据

android - Div 在 Android 上居中对齐但在 iPhone 上不居中

java - Thread.stop() - 已弃用

Python:服务多个用户的最佳方式?

ios - RestKit:为外键关系创建 stub

ios - 我可以 "manually"将项目插入 AFIncrementalStore 的缓存吗?

ios - 如何在不转换为 UIImage 的情况下在 IOS 4 中直接旋转 CVImageBuffer 图像?

ios - 在 UITableview 的 headerview 中将动态图像添加到 UIView