title: iCloud Core Data Migration
body: <p>I am developing an iOS 7 only application and I am fairly new to iCloud and Core data.
  My assumption is that the user always wants to use iCloud for Backup if possible. That is why I set up my persistence store as follows:</p>
  
  <pre><code>- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
  
   if (__persistentStoreCoordinator != nil) {
  
        return __persistentStoreCoordinator;
  
   }
  
   NSURL *storeURL = [[[self applicationDocumentsDirectory]
  
                                  URLByAppendingPathComponent:storeNameWithoutFileExtension isDirectory:NO]
  
                                 URLByAppendingPathExtension:@"sqlite"];
  
   NSError *error = nil;
  
   __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
  
  
  
   [[NSNotificationCenter defaultCenter] addObserver:self
  
                                                      selector:@selector(persistentStoreDidImportUbiquitiousContentChanges:)
  
                                                           name:NSPersistentStoreDidImportUbiquitousContentChangesNotification
  
                                                        object:__persistentStoreCoordinator];
  
  
  
   [[NSNotificationCenter defaultCenter] addObserver:self
  
                                                      selector:@selector(storesWillChange:)
  
                                                           name:NSPersistentStoreCoordinatorStoresWillChangeNotification
  
                                                        object:__persistentStoreCoordinator];
  
  
  
   [[NSNotificationCenter defaultCenter] addObserver:self
  
                                                      selector:@selector(storesDidChange:)
  
                                                           name:NSPersistentStoreCoordinatorStoresDidChangeNotification
  
                                                        object:__persistentStoreCoordinator];
  
  
  
  
  
   NSDictionary *options = @{ NSInferMappingModelAutomaticallyOption : @YES,
  
                                    NSPersistentStoreUbiquitousContentNameKey : storeNameWithoutFileExtension, };
  
  // NSPersistentStoreRebuildFromUbiquitousContentOption
  
  // NSMigratePersistentStoresAutomaticallyOption: @YES,
  
  // NSMigratePersistentStoresAutomaticallyOption : @YES,
  
  
  
   if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
  
                                                               configuration:nil
  
                                                                           URL:storeURL
  
                                                                      options:options
  
                                                                         error:&amp;error])
  
   {
  
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
  
        abort();
  
   }
  
  
  
   return __persistentStoreCoordinator;
  
  }
  </code></pre>
  
  <p>With this setup I always immediately start using the folders under Documents/CoreDataUbiquitySupport even if the user is not logged in to iCloud (using "local" folder).</p>
  
  <p>As you can see I am registering for Notifications.</p>
  
  <ul>
  <li>Why are the added and removed persistence stores in the arrays of the keys NSAddedPersistentStoresKey and NSRemovedPersistentStoresKey in the NSNotifications of NSPersistentStoreCoordinatorStoresWillChangeNotification and NSPersistentStoreCoordinatorStoresDidChangeNotification always identical e.g. for the case account added?
  One would expect that the notification contains the removed persistence store and the newly added. So they should not be the same. But unfortunately they are always the same.</li>
  </ul>
  
  <p>The current behaviour is if I switch accounts or log out of an account or log in to a new account the app always starts with the associated store or a new one if there was none before. My desired behaviour would be that the app always migrates the data to the new store. E.g.: User is not logged in to iCloud and starts using my app. He creates data which is saved under local in Documents/CoreDataUbiquitySupport. Now he turns on iCloud. Now I want the local data to be migrated to the cloud. Currently this is not happening.
  In which method do I have to implement the migration and how exactly do I implement it? Can I use the method "migratePersistentStore"? I tried to use the following code in NSPersistentStoreCoordinatorStoresDidChangeNotification but to no avail:</p>
  
  <pre><code> - (void)storesDidChange:(NSNotification *)n {
  
   // refresh user interface
   switch ([[n.userInfo objectForKey:NSPersistentStoreUbiquitousTransitionTypeKey] integerValue]) {
  
        case NSPersistentStoreUbiquitousTransitionTypeAccountAdded : {
  
             NSLog(@"NSPersistentStoreUbiquitousTransitionTypeAccountAdded migrate");
  
  
             NSError *error = nil;
  
             NSURL *storeURL = ((NSPersistentStore *)asdf[0]).URL;
  
             NSDictionary *options = @{ NSMigratePersistentStoresAutomaticallyOption : @YES,
  
                                              NSInferMappingModelAutomaticallyOption : @YES,
  
                                              NSPersistentStoreUbiquitousContentNameKey : storeNameWithoutFileExtension, };
  
             NSPersistentStore *asdfasdf = [__persistentStoreCoordinator migratePersistentStore:self.oldStore toURL:storeURL options:options withType:NSSQLiteStoreType error:&amp;error];
        }
  
        break;
  
        case NSPersistentStoreUbiquitousTransitionTypeAccountRemoved :
  
             NSLog(@"NSPersistentStoreUbiquitousTransitionTypeAccountRemoved");
  
  
  
             break;
  
        case NSPersistentStoreUbiquitousTransitionTypeContentRemoved : {
  
             NSLog(@"NSPersistentStoreUbiquitousTransitionTypeContentRemoved migrate");
  
             NSError *error = nil;
  
             NSURL *storeURL = ((NSPersistentStore *)asdf[0]).URL;
  
             NSDictionary *options = @{ NSMigratePersistentStoresAutomaticallyOption : @YES,
  
                                              NSInferMappingModelAutomaticallyOption : @YES,
  
                                              NSPersistentStoreUbiquitousContentNameKey : storeNameWithoutFileExtension, };
  
             NSPersistentStore *asdfasdf = [__persistentStoreCoordinator migratePersistentStore:self.oldStore toURL:storeURL options:options withType:NSSQLiteStoreType error:&amp;error];
  
        }
  
        break;
  
        case NSPersistentStoreUbiquitousTransitionTypeInitialImportCompleted :
  
             NSLog(@"NSPersistentStoreUbiquitousTransitionTypeInitialImportCompleted");
  
             NSLog(@"initial import");
  
  
  
             break;
  
        default :
  
             break;
  
   }
  
  }
  </code></pre>
  
  <p>The variable oldStore was set in the NSPersistentStoreCoordinatorStoresWillChangeNotification since I could not rely on the NSNotification and its keys NSAddedPersistentStoresKey and NSRemovedPersistentStoresKey because as previously states both arrays always contain the same stores as previously described.</p>
  
  <ul>
  <li><p>In which method/at what point would I implement deduplication code? Can I do it in one of the notifications?</p></li>
  <li><p>For which usecase do I have to use NSMigratePersistentStoresAutomaticallyOption? How does that option work exactly?</p></li>
  </ul>
  
  <p>A weird behaviour I have seen while playing around with my app is that if the user is not logged in to iCloud. When I bring my app to the background and I log out of iCloud and go back to my App the NSNotifications I get are of type NSPersistentStoreUbiquitousTransitionTypeContentRemoved. I would expect NSPersistentStoreUbiquitousTransitionTypeAccountRemoved. If I then bring the app to background and back up again I get NSNotifications with type NSPersistentStoreUbiquitousTransitionTypeAccountRemoved. But unfortunately NSPersistentStoreCoordinatorStoresWillChangeNotification and NSPersistentStoreCoordinatorStoresDidChangeNotification are always fired for the usecase when the user is not logged in to the iCloud and the app is running and the user brings the app to the background and then back to the foreground and I get NSNotifications with type NSPersistentStoreUbiquitousTransitionTypeAccountRemoved. And this always happens.
  - Why is that?</p>
  
  <p>To make my used code complete here is my code for the NSPersistentStoreCoordinatorStoresWillChangeNotification and the NSPersistentStoreDidImportUbiquitousContentChangesNotification and a couple other functions:</p>
  
  <pre><code>- (void)storesWillChange:(NSNotification *)n {
  
   NSLog(@"storesWillChange");
  
   NSArray *pStores = self.persistentStoreCoordinator.persistentStores;
   NSManagedObjectContext *moc = [self managedObjectContext];
  
  
  
   switch ([[n.userInfo objectForKey:NSPersistentStoreUbiquitousTransitionTypeKey] integerValue]) {
  
        case NSPersistentStoreUbiquitousTransitionTypeAccountAdded : {
  
             NSLog(@"NSPersistentStoreUbiquitousTransitionTypeAccountAdded");
  
             self.oldStore = pStores[0];
  
        }
  
        break;
  
        case NSPersistentStoreUbiquitousTransitionTypeAccountRemoved :
  
             NSLog(@"NSPersistentStoreUbiquitousTransitionTypeAccountRemoved");
  
  
  
             break;
  
        case NSPersistentStoreUbiquitousTransitionTypeContentRemoved :
  
             NSLog(@"NSPersistentStoreUbiquitousTransitionTypeContentRemoved");
  
             self.oldStore = pStores[0];
  
             break;
  
        case NSPersistentStoreUbiquitousTransitionTypeInitialImportCompleted :
  
             NSLog(@"NSPersistentStoreUbiquitousTransitionTypeInitialImportCompleted");
  
             NSLog(@"initial import");
  
  
  
             break;
  
        default :
  
             break;
  
   }
  
   [moc performBlockAndWait:^{
  
         NSError *error = nil;
  
         if ([moc hasChanges]) {
  
              [moc save:&amp;error];
  
         }
  
         [moc reset];
  
    }];
  
  
   // reset user interface
  
  
   }
  
  
  
  
  - (void)persistentStoreDidImportUbiquitiousContentChanges:(NSNotification    *)changeNotification {
  
   NSLog(@"*** Incoming iCloud Data ***");
  
   NSManagedObjectContext *moc = [self managedObjectContext];
  
  
  
   [moc performBlock:^{
  
         [moc mergeChangesFromContextDidSaveNotification:changeNotification];
  
    }];
  
   }
  
  
  
  
   - (NSManagedObjectContext *)managedObjectContext {
  
   if (__managedObjectContext != nil) {
  
        return __managedObjectContext;
  
   }
  
  
  
   NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
  
   if (coordinator != nil) {
  
        __managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
  
   //          __managedObjectContext = [[NSManagedObjectContext alloc] init];
  
        [__managedObjectContext setPersistentStoreCoordinator:coordinator];
  
        [__managedObjectContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
  
   }
  
   return __managedObjectContext;
  
   }
  
  
   - (NSManagedObjectModel *)managedObjectModel {
  
   if (__managedObjectModel != nil) {
  
        return __managedObjectModel;
  
   }
  
   NSURL *modelURL = [[NSBundle mainBundle] URLForResource:dataModelName withExtension:@"momd"];
  
   __managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
  
   return __managedObjectModel;
  
   }
  </code></pre>
  
  <p>So basically what I want to accomplish is that the user has the same data no matter which iCloud account he is using even if it is "local".</p>
  
  <p>Any help would be appreciated. Thank you in advance!</p>