Обновление основного хранилища данных для поддержки групп приложений


У меня есть приложение уже в App Store, которое использует данные ядра для сохранения данных.
Теперь, когда iOS 8 вот-вот выйдет, я хочу добавить к нему виджет, поэтому я должен использовать группы приложений для обмена данными между двоичными файлами.
Одна из проблем - мне нужно изменить местоположение магазина для поддержки групп приложений для всех существующих пользователей.
Я написал следующий код, пытаясь переместить хранилище на новый путь:

// Returns the persistent store coordinator for the application.
// If the coordinator doesn't already exist, it is created and the application store added to it.
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    if (_persistentStoreCoordinator != nil) {
        return _persistentStoreCoordinator;
    }

    NSURL *oldStoreURL = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
    oldStoreURL = [oldStoreURL URLByAppendingPathComponent:@"Schooler.sqlite"];


    NSURL *storeURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.com.schooler.mycontainer"];
    storeURL = [storeURL URLByAppendingPathComponent:@"Schooler.sqlite"];


    if([[NSFileManager defaultManager] fileExistsAtPath:oldStoreURL.path] == YES && [[NSFileManager defaultManager] fileExistsAtPath:storeURL.path] == NO)
    {
        // Prior today extension - Need to move to new directory
        NSError *error = nil;
        if([[NSFileManager defaultManager] moveItemAtURL:oldStoreURL toURL:storeURL error:&error] == YES)
            NSLog(@"Migrated successfully to new database location.");
        else
            NSLog(@"error: %@",error);
    }

    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                             [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

    NSError *error = nil;
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    }

    return _persistentStoreCoordinator;
}

Выход всегда "успешно перенесен в новое местоположение базы данных". Хотя все данные, сохраненные в приложении до этого, были удалены, как будто он создал новую базу данных, а не просто ее перемещает.
< бр /" > Что вызывает проблему? Как его исправить?
Спасибо.

Ответ 1

Основные данные. Хранилище NSSQLiteStoreType, созданное с параметрами по умолчанию, фактически представляет собой несколько файлов, как описано в Технический Q & A 1809: Новый режим ведения журнала по умолчанию для хранилищ Core Data SQLite в iOS 7 и OS X Mavericks. Это важно помнить при попытке переместить хранилище за пределы процесса миграции и является источником вашей проблемы - вы перемещаете один файл, когда вам нужно перемещать все из них. Однако перемещение файлов отдельно за пределами Core Data и без преимуществ файлового координатора не рекомендуется. Вместо этого лучше использовать миграцию.

Миграция приведет данные из хранилища источника и перенесет их в новое хранилище, по существу, реплицируя старые данные в новое место. Старые данные по-прежнему будут существовать в файловой системе. В своем приложении вы должны выполнить миграцию так, как сейчас, но не пытайтесь переместить старые данные в новое место самостоятельно - вот что происходит в этом случае.

Вместо того, чтобы перемещать файлы вокруг себя, вы можете рассчитывать на миграцию, чтобы переместить данные для вас. Во-первых, добавьте хранилище в постоянный координатор хранилища с URL-адресом исходных данных. Затем вы выполните перенос для перемещения этих данных на новый URL

NSPersistentStore   *sourceStore        = nil;
NSPersistentStore   *destinationStore   = nil;
NSDictionary        *storeOptions       = @{ NSSQLitePragmasOption : @{ @"journal_mode" :
  @"WAL" } };

// Add the source store
if (![coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:oldStoreURL options:storeOptions error:&error]){
    // Handle the error
} else {
    sourceStore = [coordinator persistentStoreForURL:oldStoreURL];
    if (sourceStore != nil){
        // Perform the migration
        destinationStore = [coordinator migratePersistentStore:sourceStore toURL:storeURL options:storeOptions withType:NSSQLiteStoreType error:&error];
        if (destinationStore == nil){
            // Handle the migration error
        } else {
            // You can now remove the old data at oldStoreURL
            // Note that you should do this using the NSFileCoordinator/NSFilePresenter APIs, and you should remove the other files
            // described in QA1809 as well.
        }
    }
}

После завершения миграции вы можете удалить старые файлы. В приведенном здесь примере явно указаны параметры журнала SQLite, это означает, что если параметры по умолчанию будут изменены в будущем, код все равно будет работать. Если вы используете разные варианты, вы должны использовать их вместо этого.