【问题标题】:What should I do after receiving an NSUbiquityIdentityDidChangeNotification?收到 NSUbiquityIdentityDidChangeNotification 后我该怎么办?
【发布时间】:2013-12-17 12:48:04
【问题描述】:

Apple 文档说我们需要注册 NSUbiquityIdentityDidChangeNotification 并将当前的 iCloud 令牌与之前存储在 NSUserDefaults 中的令牌进行比较,以检测用户是否从 文档和数据设置 em> 或切换到另一个 iCloud 帐户。

我使用标准的 UIManagedDocument 并且我的目标是 iOS 7,因此后备存储由 CoreData 自动处理。

当我发现用户启用/禁用 iCloud 或切换到另一个帐户后,我不明白我应该怎么做。我应该迁移持久存储吗?还是应该在NSPersistentStoreCoordinatorStoresDidChangeNotification 之后迁移它?还是我不应该迁移它,因为一切都由 CoreData 处理?

多次观看 WWDC 2013 207 视频后,我认为这将由 Core Data 自动处理,但我发现如果我从 iCloud 支持开始,然后我从文档和数据设置中将其关闭并插入新的 数据,然后我切换回 iCloud,我以两个不同的数据集结束。

我希望如果我发现用户禁用了 iCloud,那么本地数据库应该包含直到启用 iCloud 之前所做的最后一次更改,并且只有从这一点开始,所有内容都应该停止同步,直到再次启用 iCloud。

在 WWDC 2013 207 视频中,在 Melissa 演示中,我还注意到在 NSPersistentStoreCoordinatorStoresDidChangeNotification 之后调用了方法 [self migrateBack],这让我感到困惑,因为幻灯片只是显示我们应该在此处保存上下文并刷新 UI ,它们并没有表明我们应该迁移任何东西:

**Account Changes Now**

NSPersistentStoreCoordinatorStoresWillChangeNotification
[NSManagedObjectContext save:]
[NSManagedObjectContext reset:] 

NSPersistentStoreCoordinatorStoresDidChangeNotification
[NSManagedObjectContext save:]

【问题讨论】:

    标签: ios objective-c core-data icloud uimanageddocument


    【解决方案1】:

    NSPersistentStoreCoordinatorStoresDidChangeNotification 通知与更改 iCloud 访问权限无关。

    如果用户关闭 iCloud 访问或从 iCloud 注销,那么 Core Data 必须使用后备存储,这可能是空的!您将没有机会迁移任何内容。

    但是,如果应用程序有自己的“使用 iCloud”设置,那么您可以测试该更改,如果设置为“否”,则假设 iCloud 仍然可用,则将任何文档迁移到本地存储。

    您可以在最新版本的 Pages 中看到预期的行为。如果您有 iCloud 文档,那么一旦您在设置应用程序中关闭 iCloud 文档和数据,您就会失去对 Pages 文档的所有访问权限。但是,如果您进入设置应用程序中的 Pages 设置并关闭使用 iCloud,然后切换回 Pages,您将被提示在我的 iPhone 上保留、从我的 iPhone 中删除或继续使用 iCloud。这就是 Apple 期望您的应用运行的方式。

    当应用程序进入前台时,我们会检查应用程序特定的 iCloud 设置,如果它们发生了变化,我们会采取必要的措施。

    1. 如果没有进行任何更改,那么我们将继续运行
    2. 如果 iCloud 设置已更改,则:
      • 如果关闭,请询问用户该怎么做
      • 如果已开启,则共享 iCloud 中的所有文档

    /*!该应用程序即将进入前台,因此请借此机会检查用户是否更改了任何内容 设置。他们可能更改了 iCloud 帐户,登录或退出 iCloud,将 Documents & Data 设置为关闭(效果与 如果他们退出了 iCloud)或者他们可能已经更改了应用程序的特定设置。 如果设置已更改,请检查是否关闭了 iCloud,并询问用户是否要在本地保存文件。 否则只需将文件复制到 iCloud(不要再询问用户,他们刚刚打开了 iCloud,所以他们显然是认真的!)

    @param application 应用程序 */

    - (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];
    }
    

    【讨论】:

    • 我的应用没有自己的使用 iCloud 设置并且永远不会有。用户将从设置应用程序启用/禁用 iCloud。那么收到 NSUbiquityIdentityDidChangeNotification 后我该怎么办呢?问他像 Pages 示例中那样做什么,然后迁移?顺便说一句,感谢您这些天给我的 iCloud 支持!
    • 如果用户关闭了 iCloud,您将无法迁移,因为您只能访问后备存储。用户必须重新打开 iCloud 才能访问数据,然后您必须提供一些其他选项 - 因此需要特定于应用程序的设置。请注意,应用程序特定设置仍然在设备设置应用程序中设置,它在您的应用程序中不可用。您只需在您的应用程序中包含一个设置包,这将导致 iOS 设置应用程序创建一个特定于您的应用程序的条目。查看页面设置的设置向下滚动第一页
    • 抱歉,我没有页面。如果我查看 Document & Settigns 应用程序,在 iCloud -> Documents & Data 下,我已经看到了我的应用程序的开/关开关。你指的是它吗?这是自动创建的,如果设备启用了 iCloud,它会自动设置为开启,对我来说,这也意味着我不应该打扰用户询问他是否想在第一次运行应用程序时使用 iCloud。我猜 Apple 提供的 iCloud 设计指南没有更新!
    • 不,这只是对全局设置的改进。页面是免费的,下载它。您将在与 iCloud 选项相同的页面上看到应用程序设置,只需进一步向下滚动即可。是的,他们的文档不是最新的,他们拒绝了我的应用程序,直到我做了 Pages 所做的事情。
    • "但是,如果您进入设置应用程序中的 Pages 设置并关闭使用 iCloud,然后切换回 Pages,您将被提示在我的 iPhone 上保留、从我的 iPhone 中删除或继续使用 iCloud。这就是 Apple 期望你的应用程序运行的方式。”好的,我明白了你的意思,这和他们在 Garage Band 中所做的一样。您能否发布一些代码,向我展示您对保留/删除/继续使用 iCloud 的反应?
    猜你喜欢
    • 1970-01-01
    • 2021-08-20
    • 2021-10-24
    • 2022-08-12
    • 2019-06-01
    • 2021-10-01
    • 2022-11-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多