Search code examples
objective-cswiftcore-dataconcurrencymagicalrecord

Core data: concurency conflict between save and fetch


These two function calls seem to be conflicting:

    MagicalRecord.save({ (localContext) in
        let items = NewsItem.staleNewsItems(in: localContext)
        if ((items?.count)! > 0){
            items?.forEach({ (item) in
                if let object = item as? NSManagedObject {
                    object.mr_deleteEntity(in: localContext)
                }
            })
        }
    })

and

- (void) buildAndFetchFRCsInContext:(NSManagedObjectContext*)context {
self.newsItemsFRC = [self buildFetchResultsControllerForClass:[NewsItem class] sortedBy:@"id" withPredicate:nil inContext:context];

[context performBlock:^{
    __unused NSDate* start = [NSDate date];
    NSError* error;

    [self.newsItemsFRC performFetch:&error]; // this line crashes
    [self calculateAndBroadcastCounts];
}];
}

Is this save call thread safe? If so what could cause these two functions to cause each-other to crash?


Solution

  • The issue is I'm modifying the news items outside of the context they were created in. So to fix the issue I had to move the code to the main thread. I switched from using magical records save to just performBlockAndWait which is guaranteed to run on the calling thread:

    private static func cleanUpNewsItems() -> Void {
        let context = NSManagedObjectContext.mr_()
        context.performAndWait { 
            var itemsToDelete = [NSManagedObject]()
            if let items = NewsItem.staleNewsItems(in: context) {
                items.forEach({ (item) in
                    itemsToDelete.append(item as! NSManagedObject)
                })
            }
            for item in itemsToDelete {
                context.delete(item)
            }
            do {
                try context.save()
            } catch let error as NSError {
                print("Error While Deleting Note: \(error.userInfo)")
            }
        }
    }