Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Magical Record - fetch in main thread block ui, in background return nil

I'm new to Magical Record, but already have seen a few questions on stackoverflow, and can't find an answer to my question.

I have to find items with the predicate using this type of construction:

NSArray *result = [MOSomeItems MR_findAllWithPredicate:predicate];

On the main thread result returns some value, but the UI is freezing.

When using this construction, result returns nil value:

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSArray *result = [MOSomeItems MR_findAllWithPredicate:predicate];
});

What is the best practice for fetching data in background?

like image 593
yarchiko Avatar asked Dec 04 '22 07:12

yarchiko


1 Answers

You need to use a context with a private queue, and then pull the results out from the main context using the fetched IDs.

// Create a child context of our main context
NSManagedObjectContext *privateContext = [NSManagedObjectContext MR_context];
// When using private contexts you must execute the core data code in it's private queue using performBlock: or performBlockAndWait:
[privateContext performBlock:^{
  // Execute your fetch
  NSArray *privateObjects = [MOSomeItems MR_findAllWithPredicate:predicate inContext:privateContext];
  // Convert your fetched objects into object IDs which can be pulled out of the main context
  NSArray *privateObjectIDs = [privateObjects valueForKey:@"objectID"];
  // Return to our main thread
  dispatch_async(dispatch_get_main_queue(), ^{
    // Create a new predicate to use to pull our objects out
    NSPredicate *mainPredicate = [NSPredicate predicateWithFormat:@"self IN %@", privateObjectIDs];
    // Execute your fetch
    NSArray *finalResults = [MOSomeItems MR_findAllWithPredicate:mainPredicate];
    // Now you can use finalResults however you need from the main thread
  });
}];

You can also pull objects out using the -[NSManagedObjectContext objectWithID:] method, passing each of the objects in the privateObjectIDs array as the argument, but this way is shorter. I also suggest you look into creating a fetch request (MagicalRecord has a MR_fetchAllWithPredicate: method), setting a batch size, and executing the fetch manually. This will allow Core Data to pull your data in chunks, all behind the scenes of the returned array, to prevent blocking of your thread.

Hope that helps!

like image 74
James Richard Avatar answered Jan 21 '23 20:01

James Richard