Skip to content

Instantly share code, notes, and snippets.

@mluisbrown
Last active January 1, 2025 22:35
Show Gist options
  • Select an option

  • Save mluisbrown/7015953 to your computer and use it in GitHub Desktop.

Select an option

Save mluisbrown/7015953 to your computer and use it in GitHub Desktop.

Revisions

  1. mluisbrown revised this gist Oct 16, 2013. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion AppDelegate.m
    Original file line number Diff line number Diff line change
    @@ -12,7 +12,7 @@ @implementation AppDelegate

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
    self.persistentStack = [[PersistentStack alloc] initWithStoreURL:self.storeURL tutorialURL:self.tutorialURL modelURL:self.modelURL tutorialMode:NO];
    self.persistentStack = [[PersistentStack alloc] initWithStoreURL:self.storeURL modelURL:self.modelURL];
    self.managedObjectContext = self.persistentStack.managedObjectContext;

    // Override point for customization after application launch.
  2. mluisbrown created this gist Oct 16, 2013.
    8 changes: 8 additions & 0 deletions AppDelegate.h
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,8 @@
    @import UIKit;
    #import "PersistentStack.h"

    @interface AppDelegate : UIResponder <UIApplicationDelegate>

    @property (strong, nonatomic) UIWindow *window;

    @end
    61 changes: 61 additions & 0 deletions AppDelegate.m
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,61 @@
    #import "AppDelegate.h"
    #import "PersistentStack.h"

    @interface AppDelegate ()

    @property (nonatomic, strong) NSManagedObjectContext* managedObjectContext;
    @property (nonatomic, strong) PersistentStack* persistentStack;

    @end

    @implementation AppDelegate

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
    self.persistentStack = [[PersistentStack alloc] initWithStoreURL:self.storeURL tutorialURL:self.tutorialURL modelURL:self.modelURL tutorialMode:NO];
    self.managedObjectContext = self.persistentStack.managedObjectContext;

    // Override point for customization after application launch.
    return YES;
    }

    - (void)applicationWillResignActive:(UIApplication *)application
    {
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
    }

    - (void)applicationDidEnterBackground:(UIApplication *)application
    {
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
    [self.managedObjectContext save:NULL];
    }

    - (void)applicationWillEnterForeground:(UIApplication *)application
    {
    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
    }

    - (void)applicationDidBecomeActive:(UIApplication *)application
    {
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    }

    - (void)applicationWillTerminate:(UIApplication *)application
    {
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    }

    - (NSURL*)storeURL
    {
    NSURL* documentsDirectory = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:NULL];
    return [documentsDirectory URLByAppendingPathComponent:@"MyApp.sqlite"];
    }

    - (NSURL*)modelURL
    {
    return [[NSBundle mainBundle] URLForResource:@"MyApp" withExtension:@"momd"];
    }

    @end
    10 changes: 10 additions & 0 deletions PersistentStack.h
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,10 @@
    @import Foundation;
    @import CoreData;

    @interface PersistentStack : NSObject

    - (id)initWithStoreURL:(NSURL *)storeURL modelURL:(NSURL *)modelURL;

    @property (nonatomic,strong,readonly) NSManagedObjectContext *managedObjectContext;

    @end
    131 changes: 131 additions & 0 deletions PersistentStack.m
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,131 @@
    #import "PersistentStack.h"

    @interface PersistentStack ()

    @property (nonatomic,strong,readwrite) NSManagedObjectContext* managedObjectContext;
    @property (nonatomic,strong) NSURL* modelURL;
    @property (nonatomic,strong) NSURL* storeURL;

    @end

    @implementation PersistentStack

    - (id)initWithStoreURL:(NSURL*)storeURL modelURL:(NSURL*)modelURL
    {
    self = [super init];
    if (self) {
    self.storeURL = storeURL;
    self.modelURL = modelURL;
    [self setupManagedObjectContext];
    }
    return self;
    }

    - (void)setupManagedObjectContext
    {
    self.managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    self.managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
    self.managedObjectContext.persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel];


    __weak NSPersistentStoreCoordinator *psc = self.managedObjectContext.persistentStoreCoordinator;

    // iCloud notification subscriptions
    NSNotificationCenter *dc = [NSNotificationCenter defaultCenter];
    [dc addObserver:self
    selector:@selector(storesWillChange:)
    name:NSPersistentStoreCoordinatorStoresWillChangeNotification
    object:psc];

    [dc addObserver:self
    selector:@selector(storesDidChange:)
    name:NSPersistentStoreCoordinatorStoresDidChangeNotification
    object:psc];

    [dc addObserver:self
    selector:@selector(persistentStoreDidImportUbiquitousContentChanges:)
    name:NSPersistentStoreDidImportUbiquitousContentChangesNotification
    object:psc];

    NSError* error;
    // the only difference in this call that makes the store an iCloud enabled store
    // is the NSPersistentStoreUbiquitousContentNameKey in options. I use "iCloudStore"
    // but you can use what you like. For a non-iCloud enabled store, I pass "nil" for options.

    // Note that the store URL is the same regardless of whether you're using iCloud or not.
    // If you create a non-iCloud enabled store, it will be created in the App's Documents directory.
    // An iCloud enabled store will be created below a directory called CoreDataUbiquitySupport
    // in your App's Documents directory
    [self.managedObjectContext.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
    configuration:nil
    URL:self.storeURL
    options:@{ NSPersistentStoreUbiquitousContentNameKey : @"iCloudStore" }
    error:&error];
    if (error) {
    NSLog(@"error: %@", error);
    }
    }

    - (NSManagedObjectModel*)managedObjectModel
    {
    return [[NSManagedObjectModel alloc] initWithContentsOfURL:self.modelURL];
    }

    // Subscribe to NSPersistentStoreDidImportUbiquitousContentChangesNotification
    - (void)persistentStoreDidImportUbiquitousContentChanges:(NSNotification*)note
    {
    NSLog(@"%s", __PRETTY_FUNCTION__);
    NSLog(@"%@", note.userInfo.description);

    NSManagedObjectContext *moc = self.managedObjectContext;
    [moc performBlock:^{
    [moc mergeChangesFromContextDidSaveNotification:note];

    // you may want to post a notification here so that which ever part of your app
    // needs to can react appropriately to what was merged.
    // An exmaple of how to iterate over what was merged follows, although I wouldn't
    // recommend doing it here. Better handle it in a delegate or use notifications.
    // Note that the notification contains NSManagedObjectIDs
    // and not NSManagedObjects.
    NSDictionary *changes = note.userInfo;
    NSMutableSet *allChanges = [NSMutableSet new];
    [allChanges unionSet:changes[NSInsertedObjectsKey]];
    [allChanges unionSet:changes[NSUpdatedObjectsKey]];
    [allChanges unionSet:changes[NSDeletedObjectsKey]];

    for (NSManagedObjectID *objID in allChanges) {
    // do whatever you need to with the NSManagedObjectID
    // you can retrieve the object from with [moc objectWithID:objID]
    }

    }];
    }

    // Subscribe to NSPersistentStoreCoordinatorStoresWillChangeNotification
    // most likely to be called if the user enables / disables iCloud
    // (either globally, or just for your app) or if the user changes
    // iCloud accounts.
    - (void)storesWillChange:(NSNotification *)note {
    NSManagedObjectContext *moc = self.managedObjectContext;
    [moc performBlockAndWait:^{
    NSError *error = nil;
    if ([moc hasChanges]) {
    [moc save:&error];
    }

    [moc reset];
    }];

    // now reset your UI to be prepared for a totally different
    // set of data (eg, popToRootViewControllerAnimated:)
    // but don't load any new data yet.
    }

    // Subscribe to NSPersistentStoreCoordinatorStoresDidChangeNotification
    - (void)storesDidChange:(NSNotification *)note {
    // here is when you can refresh your UI and
    // load new data from the new store
    }


    @end