Отключение iCloud в Core Data (также известное как перенос файла постоянного хранилища на локальный) в iOS 7

Я использую новый API iOS 7 для синхронизации Core Data с iCloud. Это довольно простой и понятный API, но я не могу найти рабочий способ отключить его и снова использовать локальное хранилище. Без потери данных.

Я создаю свой iCloud persistantStore вот так. Это работает как шарм.

[[context persistentStoreCoordinator] addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[NSURL fileURLWithPath:[self iCloudFilePath]] options:@{ NSPersistentStoreUbiquitousContentNameKey: @"Favorite" } error:&error];

Однако я пытаюсь использовать новый API миграции для переноса магазина из магазина iCloud в локальный магазин следующим образом:

Метод 1 использует *icloudps в качестве хранилища, а метод 2 использует *ps в качестве хранилища.

NSPersistentStore *icloudps = [[[context persistentStoreCoordinator]
    persistentStores] objectAtIndex:0];

NSPersistentStore *ps = [[context persistentStoreCoordinator]
    addPersistentStoreWithType:NSSQLiteStoreType
    configuration:nil URL:[icloudps URL] options:nil error:&error];

[[context persistentStoreCoordinator] migratePersistentStore:icloudps
    toURL:[NSURL fileURLWithPath:[self filePath]]
    options:@{ NSPersistentStoreRemoveUbiquitousMetadataOption: @YES }
    withType:NSSQLiteStoreType error:&error];

Метод 1 приводит к этому сбою:

Завершение работы приложения из-за необработанного исключения «NSObjectInaccessibleException», причина: «CoreData не удалось выполнить ошибку для «0xd0000000000080002 x-coredata://153BBFEA-0319-4F10-AEA4-1DA12A21BFFF/Favorite/p2>»

Способ 2 в этом:

* Завершение работы приложения из-за необработанного исключения "NSInvalidArgumentException", причина: "nil не является допустимым постоянным хранилищем"

Я понятия не имею, как заставить это работать. Надеюсь, кто-то может помочь.


person Leandros    schedule 29.11.2013    source источник
comment
Попробуйте установить параметр JOURNAL=DELETE, чтобы избежать работы в режиме WAL. Возможно, вам придется каким-то образом принудительно установить контрольную точку, если существующий файл использовался в режиме WAL.   -  person Duncan Groenewald    schedule 30.11.2013
comment
Вы правы @DuncanGroenewald. Миграция работает с отключенным режимом WAL. Спасибо.   -  person Leandros    schedule 30.11.2013
comment
пожалуйста, зарегистрируйте отчет об ошибке с Apple   -  person Duncan Groenewald    schedule 01.12.2013
comment
Ну, это все еще не работает, как ожидалось. Я не уверен, где именно проблема, в реализации iCloud или где-то еще.   -  person Leandros    schedule 01.12.2013
comment
Что сейчас не работает?   -  person Duncan Groenewald    schedule 01.12.2013
comment
Получил это работает. Это не было связано с частью iCloud, это было связано с ранним обновлением (до запуска iCloud).   -  person Leandros    schedule 01.12.2013
comment
@Leandros Leandros У вас получилось работать с методом 1 или 2?   -  person Shmidt    schedule 13.02.2014


Ответы (1)


РЕДАКТИРОВАТЬ

Я только что опубликовал пример приложения Core Data в стиле библиотеки iOS, которое включает интеграцию с iCloud. Приложение включает в себя пакет настроек, позволяющий пользователю переключать настройки предпочтения «Использовать iCloud» и переносить магазин в iCloud и из него в зависимости от настроек пользователя.

Загрузите по ссылке ниже - извините за документацию - в какой-то момент это обойдется, но это работает почти так же, как пример UIManagedDocument.

http://ossh.com.au/design-and-technology/software-development/

КОНЕЦ РЕДАКТИРОВАТЬ

Если это вообще поможет, вот метод, который я использую в OS X для сохранения другой копии документа Core Data, синхронизированного с iCloud (в ответ на выбор пользователем пункта меню «Сохранить как»). По большей части iOS должна работать точно так же. Также имейте в виду, что вам, возможно, придется закрыть и снова открыть документ после завершения миграции - я, кажется, вспоминаю какую-то проблему, если я этого не сделал.

/*! This method is used to build another local Core Data document, usually in response to the user selecting the 'Save As' menu option.  The document is NEVER iCloud enabled when we do this and the User can select the 'Share in iCloud' menu option once Save As is done to make the file available to other devices via iCloud.

    @param newURL The URL where the new file is to be created.
    @param typeName The type(SQLite, Binary or XML) of file to use for the new store.
    @param error  Upon return contains the error if one was encountered
    @return Returns YES if the new store was successfully created and NO if not.
 */
- (bool)buildNewStoreAtURL:(NSURL*)newURL type:(NSString *)typeName error:(NSError **)error {

    //FLOG(@"buildNewStoreAtURL:type:error: called");

    NSError *myError;

    // We only have one store so get it
    NSPersistentStore *currentStore = [self.managedObjectContext.persistentStoreCoordinator.persistentStores objectAtIndex:0];

    // Get any options it has, we assume we need to keep most of them
    NSDictionary *currentOptions = currentStore.options;

    NSMutableDictionary *newOptions = [[NSMutableDictionary alloc] initWithDictionary:currentOptions];

    // Make sure we don't use WAL mode, it has issues
    [newOptions setObject:@"DELETE" forKey:@"JOURNAL"];

    // Remove any iCloud options (this one includes the unique iCloud UUID)
    [newOptions removeObjectForKey:NSPersistentStoreUbiquitousContentNameKey];

    // Remove Core Data ubiquity metadata
    [newOptions setObject:[NSNumber numberWithBool:YES] forKey:NSPersistentStoreRemoveUbiquitousMetadataOption];

    NSPersistentStoreCoordinator *psc = self.managedObjectContext.persistentStoreCoordinator;

    // Now migrate the store to the new location
    NSPersistentStore *newStore = [psc migratePersistentStore:currentStore toURL:newURL options:newOptions withType:typeName error:&myError];

    // Now check it was successful
    if (newStore) {

        // Now set up our custom metadata so we can determine if it has been synced in iCloud next time we open it
        // We have to know this in order to pass in the correct options to the PSC
        NSDictionary *dict = [self getiCloudMetaDataForStore:[psc metadataForPersistentStore:newStore] iCloud:NO ubiquityName:nil];

        [psc setMetadata:dict forPersistentStore:newStore];

        return YES;
    }
    else {

        FLOG(@" problem creating new document");
        FLOG(@"  - error is %@, %@", myError, myError.userInfo);
        *error = myError;
        return NO;
    }

}
person Duncan Groenewald    schedule 30.11.2013
comment
Я думаю, что ключ должен быть @journal_mode, а не @JOURNAL, в соответствии с этим: sqlite.org/pragma.html# pragma_journal_mode и это: developer.apple.com/library/ios/qa/qa1809/_index.html#// - person StephenT; 16.09.2015