ioscore-datastorageexternaluimanageddocument

Moving a core data model that allows external storage into a UIManagedDocument


What is the right way to move a core data model that allows external storage into a UIManagedDocument? I have a core data store that I am trying to move into a UIManagedDocument. I have users with lots of data. Some of it is 2 - 3 minute audio clips. I am subclassing UIManaged document and overriding the configurePersistentStoreCoordinatorForURL. Then copying the files over into the UIManagedDocument bundle. It all seems to work great accept for the Audio files that are stored externally. In my Core Data Model, my audio files are set up to allow external storage. These files are no longer connected after the move and when I try to play them int the app after the move, I get an audio session error. Thanks for any help you can offer on the topic. Here is my code that I am using to override the UIMD…

- (BOOL)configurePersistentStoreCoordinatorForURL:(NSURL *)storeURL
                                       ofType:(NSString *)fileType
                           modelConfiguration:(NSString *)configuration
                                 storeOptions:(NSDictionary *)storeOptions
                                        error:(NSError *__autoreleasing *)error{
  [self printFileDir];
  // If legacy store exists, create a UIManaged Document and store it there
  NSURL *docsDir = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
  NSURL *legacyStoreURL = [docsDir URLByAppendingPathComponent:@"RRLevelBook.sqlite"];

  NSFileManager* fileManager = [NSFileManager defaultManager];
  if ([fileManager fileExistsAtPath:legacyStoreURL.path])
  {
      NSLog(@"Old db exists");

      //swap files
      NSURL *storeURLshm = [NSURL URLWithString:[[storeURL absoluteString] stringByAppendingString:@"-shm"]];
      NSURL *storeURLwal = [NSURL URLWithString:[[storeURL absoluteString] stringByAppendingString:@"-wal"]];
      NSURL *supportFiles = [[storeURL URLByDeletingLastPathComponent] URLByAppendingPathComponent:@".persistenStore_SUPPORT"];
      NSURL *legacyStoreURLshm = [NSURL URLWithString:[[legacyStoreURL absoluteString] stringByAppendingString:@"-shm"]];
      NSURL *legacyStoreURLwal = [NSURL URLWithString:[[legacyStoreURL absoluteString] stringByAppendingString:@"-wal"]];
      NSURL *legacySupportFiles = [[legacyStoreURL URLByDeletingLastPathComponent] URLByAppendingPathComponent:@".RRLevelBook_SUPPORT"];

      NSError* thisError = nil;

      //swap the sqlite file
      [fileManager replaceItemAtURL:storeURL
                    withItemAtURL:legacyStoreURL
                   backupItemName:nil
                          options:NSFileManagerItemReplacementUsingNewMetadataOnly
                 resultingItemURL:nil
                            error:&thisError];
      //swap the -shm file
      [fileManager replaceItemAtURL:storeURLshm
                    withItemAtURL:legacyStoreURLshm
                   backupItemName:nil
                          options:NSFileManagerItemReplacementUsingNewMetadataOnly
                 resultingItemURL:nil
                            error:&thisError];

      //swap the -wal file
      [fileManager replaceItemAtURL:storeURLwal
                    withItemAtURL:legacyStoreURLwal
                   backupItemName:nil
                          options:NSFileManagerItemReplacementUsingNewMetadataOnly
                 resultingItemURL:nil
                            error:&thisError];
      //Move in the Support files
      [fileManager moveItemAtURL:legacySupportFiles toURL:supportFiles error:nil];

      //delete old files that have been swapped
      [fileManager removeItemAtURL:legacyStoreURL error:nil];
      [fileManager removeItemAtURL:legacyStoreURLwal error:nil];
      [fileManager removeItemAtURL:legacyStoreURLshm error:nil];
      [fileManager removeItemAtURL:legacySupportFiles error:nil];

      NSLog(@"%@",[thisError localizedDescription]);
  }

  [self printFileDir];
  return [super configurePersistentStoreCoordinatorForURL:storeURL ofType:fileType modelConfiguration:configuration storeOptions:storeOptions error:error];
}

Solution

  • Well, here is what I ended up doing - for better or worse:

    1. Open the new UIManagedDocument.
    2. Open up the legacy Core Data Model.
    3. Copy each audio file (NSData) from Legacy CoreData Context to the UIManagedDocument Context.
    4. Reconnect all relationships based on the Legacy CoreData Context.

       NSManagedObjectContext *legacyMOC = [[NSManagedObjectContext alloc]init];
       [legacyMOC setPersistentStoreCoordinator:psc];
      
      
      //fetch all audio recordings from legacyStore
      NSArray *legacyRecordingArray = [self fetchAudioRecordingsfrom:legacyMOC];
      
      //fetch all audio recordings form UIMDStore
      NSArray *uimdRecordingArray = [self fetchAudioRecordingsfrom:self.managedObjectContext];
      
      //for each audio recording, copy the audio object from legacy and save it to UIMDStore
      for (int i = 0; i < legacyRecordingArray.count; i++) {
      
         //save audio to core data
         RunningRecord *legacyRR = (RunningRecord *)legacyRecordingArray[i];
         RunningRecord *uimdRR = (RunningRecord *)uimdRecordingArray[i];
         uimdRR.audioData =  [NSData dataWithData:legacyRR.audio.file];
         uimdRR.audio.file = nil;
      }
      
      
      if (![self.managedObjectContext save:&error]) {
          NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);
      }