Что мне делать после получения NSUbiquityIdentityDidChangeNotification?

В документации Apple говорится, что нам необходимо зарегистрироваться в NSUbiquityIdentityDidChangeNotification и сравнить текущий токен iCloud с ранее сохраненным в NSUserDefaults, чтобы определить, отключил ли пользователь iCloud в Настройки документов и данных или переключился на другую учетную запись iCloud.

Я использую стандартный UIManagedDocument и ориентируюсь на iOS 7, поэтому CoreData автоматически обрабатывает резервное хранилище.

Я не понимаю, что мне делать после того, как я обнаружил, что пользователь включил/отключил iCloud или переключился на другую учетную запись. Должен ли я перенести постоянное хранилище? Или я должен перенести его после NSPersistentStoreCoordinatorStoresDidChangeNotification? Или я никогда не должен переносить его, потому что все обрабатывается CoreData?

После просмотра видео WWDC 2013 207 несколько раз я подумал, что Core Data обработает это автоматически, но обнаружил, что если я начну с поддержки iCloud, а затем отключу ее в настройках документа и данных и вставлю новые данные, то переключусь обратно iCloud включен, я получаю два разных набора данных.

Я бы хотел, чтобы, если я обнаружу, что пользователь отключил iCloud, локальная база данных должна содержать до последнего изменения, сделанного до тех пор, пока iCloud не будет включен, и только с этого момента все должно прекратить синхронизацию, пока iCloud снова не будет включен.

В видео WWDC 2013 207 в демо Melissa я также заметил вызов метода [self migrateBack] после NSPersistentStoreCoordinatorStoresDidChangeNotification, и это меня смущает, потому что слайды просто показывают, что мы должны сохранить наш контекст здесь и обновить пользовательский интерфейс, они не показывают, что мы должны перенести что-либо:

**Account Changes Now**

NSPersistentStoreCoordinatorStoresWillChangeNotification
[NSManagedObjectContext save:]
[NSManagedObjectContext reset:] 

NSPersistentStoreCoordinatorStoresDidChangeNotification
[NSManagedObjectContext save:]

person nico9T    schedule 01.12.2013    source источник


Ответы (1)


Уведомление NSPersistentStoreCoordinatorStoresDidChangeNotification не имеет ничего общего с изменением доступа к iCloud.

Если пользователь отключает доступ к iCloud или выходит из iCloud, Core Data должен использовать резервное хранилище, которое, вероятно, пусто! У вас не будет возможности перенести что-либо.

Однако, если приложение имеет собственный параметр «Использовать iCloud», вы можете проверить это изменение и, если установлено значение НЕТ, перенести какие-либо документы в локальное хранилище, предполагая, что iCloud все еще доступен.

Вы можете увидеть ожидаемое поведение в последней версии Pages. Если у вас есть документы iCloud, то, как только вы отключите iCloud Documents & Data в приложении «Настройки», вы потеряете доступ к документам Pages. Однако, если вы перейдете к настройкам страниц в приложении «Настройки» и отключите «Использовать iCloud», а затем переключитесь обратно на «Страницы», вам будет предложено «Сохранить на моем iPhone», «Удалить с моего iPhone» или «Продолжить использовать iCloud». Именно так Apple будет ожидать, что ваше приложение будет работать.

Когда приложение выходит на передний план, мы проверяем настройки iCloud для конкретного приложения и, если они изменились, предпринимаем необходимые действия.

  1. Если никаких изменений не произошло, продолжаем работать
  2. If the iCloud setting has changed then:
    • If it is turned OFF ask the user what to do
    • Если он был включен, поделитесь всеми документами в iCloud.

/*! Приложение вот-вот перейдет на передний план, поэтому используйте эту возможность, чтобы проверить, не изменил ли пользователь какие-либо настройки. Они могли изменить учетную запись iCloud, войти или выйти из iCloud, отключить «Документы и данные» (такой же эффект, как если бы они вышли из iCloud) или они могли изменить настройки конкретного приложения. Если настройки были изменены, проверьте, отключен ли iCloud, и спросите пользователя, хотят ли они сохранить файлы локально. В противном случае просто скопируйте файлы в iCloud (не спрашивайте пользователя снова, он только что включил iCloud, так что, очевидно, он имеет в виду!)

Приложение @param Приложение */

- (void)applicationWillEnterForeground:(UIApplication *)application
{
    //LOG(@"applicationWillEnterForeground called");

    // Check if the app settings have been changed in the Settings Bundle (we use a Settings Bundle which
    // shows settings in the Devices Settings app, along with all the other device settings).
    [[NSUserDefaults standardUserDefaults] synchronize];
    NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
    bool userICloudChoice = [userDefaults boolForKey:_cloudPreferenceKey];


    // Now compare it with the current apps in memory setting to see if it has changed
    if (userICloudChoice  == useICloudStorage) {

        // No change so do nothing
        //LOG(@" iCloud choice has not changed");

    } else {

        // Setting has been changed so take action
        //LOG(@" iCloud choice has been changed!!");

        // iCloud option has been turned off
        if (!userICloudChoice) {

            //LOG(@" Ask user if they want to keep iCloud files locally ?");

            if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
                _cloudChangedAlert = [[UIAlertView alloc] initWithTitle:@"You're not using iCloud" message:@"What would you like to do with documents currently on this phone?" delegate:self cancelButtonTitle:@"Keep using iCloud" otherButtonTitles:@"Keep on My iPhone", @"Delete from My iPhone", nil];
            } else {
                _cloudChangedAlert = [[UIAlertView alloc] initWithTitle:@"You're not using iCloud" message:@"What would you like to do with documents currently on this phone?" delegate:self cancelButtonTitle:@"Keep using iCloud" otherButtonTitles:@"Keep on My iPad", @"Delete from My iPad", nil];

            }

            [_cloudChangedAlert show];
            // Handle the users response in the alert callback

        } else {

            // iCloud is turned on so just copy them across... including the one we may have open

            //LOG(@" iCloud turned on so copy any created files across");
            [[CloudManager sharedManager] setIsCloudEnabled:YES];  // This does all the work for us
            useICloudStorage = YES;

        }
    }

}

- (void)alertView:(UIAlertView*)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{

    if (alertView == _cloudChoiceAlert)
    {
        //LOG(@" _cloudChoiceAlert being processed");
        if (buttonIndex == 1) {
            //LOG(@" user selected iCloud files");
            [[NSUserDefaults standardUserDefaults] setBool:YES forKey:_cloudPreferenceKey];
            [[NSUserDefaults standardUserDefaults] setValue:@"YES" forKey:_cloudPreferenceSet];
            useICloudStorage = YES;
            [[NSUserDefaults standardUserDefaults] synchronize];

            [[CloudManager sharedManager] setIsCloudEnabled:YES];
        }
        else {
            //LOG(@" user selected local files");
            [[NSUserDefaults standardUserDefaults] setBool:NO forKey:_cloudPreferenceKey];
            [[NSUserDefaults standardUserDefaults] setValue:@"YES" forKey:_cloudPreferenceSet];
            useICloudStorage = NO;
            [[NSUserDefaults standardUserDefaults] synchronize];

            [[CloudManager sharedManager] setIsCloudEnabled:NO];
        }
    }
    if (alertView == _cloudChangedAlert)
    {   //LOG(@" _cloudChangedAlert being processed");
        if (buttonIndex == 0) {
            //LOG(@" 'Keep using iCloud' selected");
            //LOG(@" turn Use iCloud back ON");
            [[NSUserDefaults standardUserDefaults] setBool:YES forKey:_cloudPreferenceKey];
            [[NSUserDefaults standardUserDefaults] synchronize];
            useICloudStorage = YES;
        }
        else if (buttonIndex == 1) {
            //LOG(@" 'Keep on My iPhone' selected");
            //LOG(@" copy to local storage");
            useICloudStorage = NO;
            [[CloudManager sharedManager] setDeleteICloudFiles:NO];
            [[CloudManager sharedManager] setIsCloudEnabled:NO];

        }else if (buttonIndex == 2) {
            //LOG(@" 'Delete from My iPhone' selected");
            //LOG(@" delete copies from iPhone");
            useICloudStorage = NO;
            [[CloudManager sharedManager] setDeleteICloudFiles:YES];
            [[CloudManager sharedManager] setIsCloudEnabled:NO];
        }
    }

}

/*! Checks to see whether the user has previously selected the iCloud storage option, and if so then check
    whether the iCloud identity has changed (i.e. different iCloud account being used or logged out of iCloud).
    If the user has previously chosen to use iCloud and we're still signed in, setup the CloudManager 
    with cloud storage enabled.
    If no user choice is recorded, use a UIAlert to fetch the user's preference.

 */
- (void)checkUserICloudPreferenceAndSetupIfNecessary
{
    FLOG(@"checkUserICloudPreferenceAndSetupIfNecessary called");

    [[CloudManager sharedManager] setFileExtension:_fileExtension  andUbiquityID:_ubiquityContainerKey ];

    id currentToken = [[NSFileManager defaultManager] ubiquityIdentityToken];

    NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
    NSString* userICloudChoiceSet = [userDefaults stringForKey:_cloudPreferenceSet];

    bool userICloudChoice = [userDefaults boolForKey:_cloudPreferenceKey];

    userICloudChoice = [userDefaults boolForKey:_cloudPreferenceKey];

    //FLOG(@" User preference for %@ is %@", _cloudPreferenceKey, (userICloudChoice ? @"YES" : @"NO"));

    if (userICloudChoice) {

        //LOG(@" User selected iCloud");
        useICloudStorage = YES;
        [self checkUbiquitousTokenFromPreviousLaunch:currentToken];

    } else {

        //LOG(@" User disabled iCloud");
        useICloudStorage = NO;

    }

    // iCloud is active
    if (currentToken) {

        //LOG(@" iCloud is active");

        // If user has not yet set preference the prompt for them to select a preference
        if ([userICloudChoiceSet length] == 0) {

            _cloudChoiceAlert = [[UIAlertView alloc] initWithTitle:@"Choose Storage Option" message:@"Should documents be stored in iCloud or on just this device?" delegate:self cancelButtonTitle:@"Local only" otherButtonTitles:@"iCloud", nil];
            [_cloudChoiceAlert show];

        }
        else if (userICloudChoice ) {

            [[CloudManager sharedManager] setIsCloudEnabled:YES];

        }
    }
    else {
        //LOG(@" iCloud is not active");
        [[CloudManager sharedManager] setIsCloudEnabled:NO];
        useICloudStorage = NO;
        [[NSUserDefaults standardUserDefaults] setBool:NO forKey:_cloudPreferenceKey];
        [[NSUserDefaults standardUserDefaults] synchronize];

        // Since the user is signed out of iCloud, reset the preference to not use iCloud, so if they sign in again we will prompt them to move data
        [userDefaults removeObjectForKey:_cloudPreferenceSet];
    }

    [self storeCurrentUbiquityToken:currentToken];
}
person Duncan Groenewald    schedule 01.12.2013
comment
В моем приложении нет собственной настройки использования iCloud и никогда не будет. Пользователь будет включать / отключать iCloud из приложения «Настройки». Итак, что мне делать после получения NSUbiquityIdentityDidChangeNotification? Спросите его, что делать, как в примере со страницами, а затем мигрировать? Кстати, спасибо за поддержку iCloud, которую вы оказываете мне в эти дни! - person nico9T; 02.12.2013
comment
Вы не можете выполнить миграцию, если пользователь отключил iCloud, потому что у вас есть доступ только к запасному хранилищу. Пользователь должен снова включить iCloud, чтобы получить доступ к данным, а затем вам нужно будет предоставить какой-либо другой вариант — отсюда и необходимость в настройке для конкретного приложения. Обратите внимание, что настройка конкретного приложения по-прежнему установлена ​​в приложении «Настройки устройства», а не в вашем приложении. Вы просто включаете пакет настроек в свое приложение, и это приведет к тому, что приложение настроек iOS создаст запись, специфичную для вашего приложения. Посмотрите в настройках для настроек страниц, прокрутите первую страницу вниз. - person Duncan Groenewald; 02.12.2013
comment
Извините, у меня нет страниц. Если я загляну в приложение «Документы и настройки» в iCloud -> «Документы и данные», я уже увижу переключатель включения/выключения для своего приложения. Вы имеете в виду это? Это создается автоматически, и если устройство поддерживает iCloud, оно автоматически включается, для меня это также означает, что я не должен беспокоить пользователя вопросом, хочет ли он использовать iCloud при первом запуске приложения. Я предполагаю, что руководства по дизайну iCloud, доступные от Apple, не обновляются! - person nico9T; 02.12.2013
comment
Нет, это просто уточнение глобальных настроек. Страницы бесплатны, скачайте. Вы увидите настройки приложения на той же странице, что и параметр iCloud, просто прокрутите вниз. Да, их документы не очень актуальны, они отклонили мое приложение, пока я не сделал то, что делает Pages. - person Duncan Groenewald; 02.12.2013
comment
Однако, если вы перейдете к настройкам страниц в приложении «Настройки» и отключите «Использовать iCloud», а затем переключитесь обратно на «Страницы», вам будет предложено «Сохранить на моем iPhone», «Удалить с моего iPhone» или «Продолжить использовать iCloud». Именно так Apple будет ожидать, что ваше приложение будет работать. Хорошо, я понял, что вы имели в виду, это то же самое, что и в Garage Band. Не могли бы вы опубликовать код, чтобы показать мне, как вы реагируете на сохранение/удаление/продолжение использования iCloud? - person nico9T; 02.12.2013
comment
Конечно, завтра найду что-нибудь для вас. - person Duncan Groenewald; 02.12.2013
comment
Спасибо, приятель, пожалуйста, добавьте это в свой ответ, чтобы другие могли извлечь из него уроки. В то же время я изучаю и внедряю материал для набора настроек. Теперь также имеет смысл спрашивать пользователя, должен ли он использовать iCloud! - person nico9T; 02.12.2013