You should probably be using NSFetchedResultsController. It will manage batching for you and only load what you need at the time. It's not just for table views. You can do this without a separate thread (as long as your DB isn't too big, and your fetch does not have too complex predicate that requires visiting every record in the DB).
As an alternative to FRC, or in the case of needing all records, you can use a separate thread, which will fetch objects, then present them to the main thread.
These are difficult concepts to explain in a single SO answer, so if it still does not make sense, consult the Core Data Concurrency Programming Guide.
Or, if you want to load it all, and have some control, you can do something like this. NOTE: I think this dual MOC pattern is the way to go anyway, because it makes it easier to do backgrounding anyway. For that matter, if you use UIManagedDocument, you get most of this for free anyway.
Note, this will probably take longer overall to load, but it will free up the UI thread.
NSManagedObjectContext *workerMoc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
workerMoc.persistentStoreCoordinator = psc;
// The "mainMoc" will be a child of the worker
NSManagedObjectContext *mainMoc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
mainMoc.parentContext = workerMoc;
Then when loading...
// The actual work will run in the background on the worker queue
// The "worker" queue will do the fetching and faulting, then pass object IDs
// to the mainMoc, which will fault its MOs from the parent
[workerMoc performBlock:^{
NSFetchRequest *fetchRequest = // Create fetch request
NSArray *fetchResults = [workerMoc executeFetchRequest:fetchRequest error:0];
[fetchResults enumerateObjectsUsingBlock:^(NSManagedObject *obj, NSUInteger idx, BOOL *stop) {
// Probably want to fault the object in before going to mainMoc
// since that can also take some time...
// Can also "batch" them in some small number of objects.
NSManagedObjectID *objectID = obj.objectID;
[mainMoc performBlock:^{
NSManagedObject *fetchedObject = [mainMoc objectWithID:objectID];
// Do something with it now that you are back on the main thread...
}];
}
}];