xCode 7.3 demo, AsyncFetchRequestEx1
Setting up the Stack
We create the core data stack called BNRCoreDataCoordinator.
1 2 3 4 5 6 7 8 |
#import <CoreData/CoreData.h> //for MOC and PSC properties @interface BNRCoreDataCoordinator : NSObject @property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext; @property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator; @end |
Then we set up the PSC and MOC…
1) Set up lazy loading accessor for NSPersistentStoreCoordinator
2) Set up lazy loading accessor for NSManagedObjectContext
Notice that the MOC is connected to the PSC:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
#pragma mark - Accessors - (NSManagedObjectContext *)managedObjectContext { if (!_managedObjectContext) { _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; _managedObjectContext.mergePolicy = [[NSMergePolicy alloc] initWithMergeType:NSMergeByPropertyStoreTrumpMergePolicyType]; _managedObjectContext.persistentStoreCoordinator = self.persistentStoreCoordinator; NSLog(@"%s - MOC created ", __FUNCTION__); } return _managedObjectContext; } - (NSPersistentStoreCoordinator *)persistentStoreCoordinator { if (!_persistentStoreCoordinator) { NSLog(@"%s - Creating PSC --", __FUNCTION__); NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"CoreDataBatching" withExtension:@"momd"]; NSLog(@"%s - url of CoreDataBatching.momd file: %@ --", __FUNCTION__, [modelURL absoluteString]); NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model]; NSURL *documentsDir = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; NSURL *storeURL = [documentsDir URLByAppendingPathComponent:@"store.sqlite"]; NSLog(@"%@", [storeURL absoluteString]); NSError *addingStoreError = nil; NSDictionary *storeOptions = @{NSMigratePersistentStoresAutomaticallyOption: @(YES), NSInferMappingModelAutomaticallyOption: @(YES)}; NSPersistentStore *store = [_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:storeOptions error:&addingStoreError]; if (!store || addingStoreError) { NSLog(@"Big problems man: %@", addingStoreError); } NSLog(@"%s - Created PSC --", __FUNCTION__); } return _persistentStoreCoordinator; } |
MOC Saving
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#pragma mark - Saving //Moc saves its changes - (BOOL)saveContext { NSLog(@"MOC SAVING CONTEXT ------ %s ---------", __FUNCTION__); BOOL success = YES; NSError *saveError = nil; if ([_managedObjectContext hasChanges] && ![_managedObjectContext save:&saveError]) { success = NO; NSLog(@"Saving failed with error: %@", saveError); } return success; } |
Inserting Data
We throw a task block on our MOC’s private background queue. That task to simply initialize an Entity object
n number of times. Core Data returns ready objects for us to initialize. Once all the Entity objects are set up,
we tell the MOC to save context.
The caller of this method will get a completion block to signify that our Entity insertions have been done.
We throw this completion block onto the main queue visual reply.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
- (void)insertInitialDataSetWithCompletion:(void (^)(BOOL))completion { __weak typeof(self) weakSelf = self; [self.managedObjectContext performBlock:^{ NSLog(@"--- put this block of insertion code in the MOC queue"); __strong typeof (weakSelf) strongSelf = weakSelf; //NSUInteger count = [strongSelf numberOfAllEntities]; NSUInteger count = 0; NSLog(@"%lu", (unsigned long)count); for (NSUInteger index = count; index < BNRCoreDataBatchingInitialSize; index++) { // return an object for us to initialize, once we set the properties, we add it // by saving the MOC context in saveContext method Entity * newEntity = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass(Entity.class) inManagedObjectContext:_managedObjectContext]; newEntity.title = [NSString stringWithFormat:@"%ld: Entity", (long)index + 1]; newEntity.acknowledged = @(NO); NSLog(@"Inserted %ld of %ld", (long)index + 1, (long)BNRCoreDataBatchingInitialSize); } BOOL success = [strongSelf saveContext]; //success is done. we gotta use the main queue to update the UI dispatch_async(dispatch_get_main_queue(), ^{ completion(success); }); }]; } |
How To Use
In your ViewController, import the core data coordinator, and implement a lazy loading accessor.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#import "BNRCoreDataCoordinator.h" @interface ViewController () { } @property (strong, nonatomic) BNRCoreDataCoordinator *coreDataCoordinator; @end @implementation ViewController #pragma mark - Accessor - (BNRCoreDataCoordinator *)coreDataCoordinator { if (!_coreDataCoordinator) { _coreDataCoordinator = [[BNRCoreDataCoordinator alloc] init]; NSLog(@"BNRCoreDataCoordinator created "); } return _coreDataCoordinator; } |
Let’s insert the data when it first appears. As you can see, when the insertion have completed,
we can do something on the UI, or just log a completion message.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
- (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; //when the view appears, let's insert all the initial data NSLog(@"%s - ", __FUNCTION__); [self.coreDataCoordinator insertInitialDataSetWithCompletion:^(BOOL success) { NSLog(@"%s-------- SUCCESS INSERTING ALL ENTITY S---------", __FUNCTION__); //with every successful insertion, we increase the progress bar }]; } |