核心数据应用程序中的UITableView不会更新第二个设备的主视图,除非应用程序重新启动,使用iCloud同步

时间:2014-07-21 19:48:51

标签: ios iphone core-data notifications icloud

亲爱的Stack Overflow人,

我使用Core Data和iCloud构建了一个应用程序。它是UITabBarController中的一个简单的4标签,每个标签都是UITableViewController。第一个选项卡名为Timeline,后跟Person,Event和Date。

使用设备1,我在控制台中显示“Using local storage: 0”时添加一些条目。当我构建第二个设备(在同一个iCloud帐户上)(iPad)时,它从Using Local Storage: 1(预期)开始,然后是0(预期)。但是,“时间轴”选项卡(这是主视图)实际上并不显示新条目,但“人员”,“事件”和“日期”选项卡确实显示了它。如果我重新启动应用程序,它会出现在时间轴中。

我每NSFetchedResultsController使用UITableViewController,并且引用了一个优秀的教程(http://pinkstone.co.uk/how-t-use-icloud-in-your-ios-apps/),在我的时间轴中,我输入了以下代码:

- (void)viewDidLoad
{
    [super viewDidLoad];

    // add iCloud observers
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(storesWillChange) name:NSPersistentStoreCoordinatorStoresWillChangeNotification object:self.managedObjectContext.persistentStoreCoordinator];

    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(storesDidChange:) name:NSPersistentStoreCoordinatorStoresDidChangeNotification object:self.managedObjectContext.persistentStoreCoordinator];

    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(mergeContent:) name:NSPersistentStoreDidImportUbiquitousContentChangesNotification object:self.managedObjectContext.persistentStoreCoordinator];

}

#pragma mark - iCloud Methods

- (void)storesWillChange {

    NSLog(@"\n\nStores WILL change notification received\n\n");

    // disbale UI
    [[UIApplication sharedApplication]beginIgnoringInteractionEvents];

    // save and reset our context
    if (self.managedObjectContext.hasChanges) {
        [self.managedObjectContext save:nil];
    } else {
        [self.managedObjectContext reset];
    }
}

- (void)storesDidChange:(NSNotification *)notification {

    NSLog(@"\n\nStores DID change notification received\n\n");

    // enable UI
    [[UIApplication sharedApplication]endIgnoringInteractionEvents];

    // update UI
    [self.timelineTableView reloadData];
}

- (void)mergeContent:(NSNotification *)notification {

    NSLog(@"!Merge Content here!");
    [self.managedObjectContext mergeChangesFromContextDidSaveNotification:notification];
}

我注意到一些奇怪的事情。

编辑清晰度 1)iPad(第二个设备)在初始导入期间或任何后续同步期间从不运行storesWillChange或storesDidChange。

2)已填充iPad的人员/事件选项卡,但时间轴未填充。只有当我重新运行应用程序或从设备1添加新条目时,iPad的时间轴才会更新。

问题

当我第一次连接到iCloud时,我需要做什么才能让iPad在时间轴标签中显示数据?这不是一个耐心的问题,因为我等了43分钟没有变化。

当重要来自iCloud的数据时,第二个设备上运行的方法是什么?这是我的关键。如果是storeDidChange,我应该在哪里放置?我尝试将通知监听器放在viewDidLoad时间线视图控制器,App代理中的applicationDidFinishLaunchingWithOptionsNSManagedObjectContext中,并且在任何情况下都不会运行。

这是仅限iOS 7的应用。

修改:进一步更新

我现在已经达到iPad(第二设备)仍未显示iCloud数据的程度,但如果我在第一台设备上添加新条目,它会合并内容并同步。

今天早上多次阅读Apple指南:https://developer.apple.com/library/prerelease/ios/documentation/DataManagement/Conceptual/UsingCoreDataWithiCloudPG/UsingSQLiteStoragewithiCloud/UsingSQLiteStoragewithiCloud.html#//apple_ref/doc/uid/TP40013491-CH3-SW4,我可以看到在添加持久存储发生之前注册storesDidChange很重要。这是有道理的,我做了这个,我从storesDidChange方法中获取NSLog。

然而,在One Time Ubiquity Store Container完成设置之后,它应该再次运行storesWillChange通知以及storesDidChange。

我的情况都没有。

参考这个页面,这看起来就像我面临的问题:http://www.zx81.org.uk/computing/programming/nsfetchedresultscontroller-and-icloud.html,用户在UITableView中重新获取。我这样做,但仍然,数据不会出现在iPad上,第一次运行并与iCloud Store同步。

但是因为它是UITabBarController,所以OTHER标签正在适当更新。它只是这个标签,已经在从后备到iCloud商店的迁移之前和之后显示。

修改:在此处添加persistentStoreCoordinator方法

如果问题出在我的persistentStoreCoordinator上,我在这里添加代码:

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    NSLog(@"Persistent Store");
    if (_persistentStoreCoordinator != nil) {
        return _persistentStoreCoordinator;
    }

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"Envylope.sqlite"];

    NSError *error = nil;
    // get a reference to your iCloud URL
    NSURL *cloudURL = [self grabCloudPath:@"iCloud"];

    // setup options depending on migration
    NSDictionary *options = nil;
    if ([[NSUserDefaults standardUserDefaults]boolForKey:@"OnLatestVersion"]) {
        options = @{                                       NSMigratePersistentStoresAutomaticallyOption : @YES,
                                                           NSInferMappingModelAutomaticallyOption : @YES,
                                                           NSPersistentStoreUbiquitousContentURLKey: cloudURL, NSPersistentStoreUbiquitousContentNameKey: @"EnvyCloud"};
        NSLog(@"Using iCloud from migration");
    }
    else
    {
        NSLog(@"Using the other store without the iCloud Migration");
        options = @{                                       NSMigratePersistentStoresAutomaticallyOption : @YES,
                                                           NSInferMappingModelAutomaticallyOption : @YES};
    }

    NSLog(@"Just before adding the persistent store");
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {

        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }

    NSLog(@"Just after adding the store");

    return _persistentStoreCoordinator;
}

我有if语句和userDefaults的原因是因为我想检查用户的应用程序是否需要迁移到新版本并在应用程序再次运行时维护该版本。我的意思是,如果我的设备上有App Store版本的数据并更新到此iCloud版本,它会将数据迁移到iCloud存储。如果我再次运行应用程序,它不会再次迁移,它只是使用iCloud存储。这可以同步,虽然我不相信这是问题(因为其他设备在其他选项卡上获取云信息),它就在这里完成。

任何正确方向的路径都会非常有用。

1 个答案:

答案 0 :(得分:2)

阿米特,

我已经完成了一些挖掘,我相信你的应用程序的iCloud部分工作正常。问题似乎在于获取的结果控制器 - 在某些设备上 - 需要重新获取。最简单的方法是收到storesDidChange通知。而不是重新加载表视图,尝试这样的事情:

- (void)storesDidChange:(NSNotification *)notification {

    NSLog(@"\n\nStores DID change notification received\n\n");

    // enable UI
    [[UIApplication sharedApplication]endIgnoringInteractionEvents];

    // update UI
    _fetchedResultsController = nil;
    [self fetchedResultsController];

}

首先,您将变量变为零,然后再次调用自定义初始化程序(根据您的应用程序进行修改)。现在该表视图应该更新并显示来自iCloud的结果​​。

关于缺少的通知:

您没有收到willChange和didChange的原因可能是因为您重新部署应用而未先将其从设备中删除。这不是一个准确的场景:如果实际的商店文件没有改变,那么iOS就不会发布这些通知。通过在重新部署之前删除应用程序,这些通知会正确发布 - 并且希望也会更新您提取的结果控制器。

希望这有帮助!