3

我有一个很难解决的问题。我有这种情况:

我的应用程序使用 CoreData 来存储对象,我想在设备之间实现 iCloud 同步......而我的应用程序需要一个初始填充数据库。

我第一次启动我的应用程序时,它将在云上填充我的数据库,并将某些 db'fields 标记为“是”为“databaseInstalled”。这些字段也在云端同步。

现在,当另一台设备第一次启动该应用程序时,我希望检索“databaseInstalled”字段以检查是否注入了一些数据,但这是错误的......

如果 databaseInstalled 为 false,我们注入数据,如果 databaseInstalled 为 true,我们等待 iCloud 同步。

问题是我异步检索persistentStoreCoordinator,因为我不想阻止正在等待从iCloud下载数据的应用程序......

那么,如果我需要填充数据库或者它已经在另一台设备上填充并且我只是从 iCloud 下载填充的数据库,我怎么能知道先验呢?

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    if((__persistentStoreCoordinator != nil)) {
        return __persistentStoreCoordinator;
    }

    __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];    
    NSPersistentStoreCoordinator *psc = __persistentStoreCoordinator;

    // Set up iCloud in another thread:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        // ** Note: if you adapt this code for your own use, you MUST change this variable:
        NSString *iCloudEnabledAppID = @"this is a secret!";

        // ** Note: if you adapt this code for your own use, you should change this variable:        
        NSString *dataFileName = @"you do not have to know.sqlite";

        // ** Note: For basic usage you shouldn't need to change anything else

        NSString *iCloudDataDirectoryName = @"Data.nosync";
        NSString *iCloudLogsDirectoryName = @"Logs";
        NSFileManager *fileManager = [NSFileManager defaultManager];        
        NSURL *localStore = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:dataFileName];
        NSURL *iCloud = [fileManager URLForUbiquityContainerIdentifier:nil];

        if (iCloud) {

            NSLog(@"iCloud is working");

            NSURL *iCloudLogsPath = [NSURL fileURLWithPath:[[iCloud path] stringByAppendingPathComponent:iCloudLogsDirectoryName]];

            NSLog(@"iCloudEnabledAppID = %@",iCloudEnabledAppID);
            NSLog(@"dataFileName = %@", dataFileName); 
            NSLog(@"iCloudDataDirectoryName = %@", iCloudDataDirectoryName);
            NSLog(@"iCloudLogsDirectoryName = %@", iCloudLogsDirectoryName);  
            NSLog(@"iCloud = %@", iCloud);
            NSLog(@"iCloudLogsPath = %@", iCloudLogsPath);

            // da rimuovere

            //[fileManager removeItemAtURL:iCloudLogsPath error:nil];
            #warning to remove

            if([fileManager fileExistsAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName]] == NO) {
                NSError *fileSystemError;
                [fileManager createDirectoryAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName] 
                       withIntermediateDirectories:YES 
                                        attributes:nil 
                                             error:&fileSystemError];
                if(fileSystemError != nil) {
                    NSLog(@"Error creating database directory %@", fileSystemError);
                }
            }

            NSString *iCloudData = [[[iCloud path] 
                                     stringByAppendingPathComponent:iCloudDataDirectoryName] 
                                    stringByAppendingPathComponent:dataFileName];

            //[fileManager removeItemAtPath:iCloudData error:nil];
#warning to remove

            NSLog(@"iCloudData = %@", iCloudData);

            NSMutableDictionary *options = [NSMutableDictionary dictionary];
            [options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
            [options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];
            [options setObject:iCloudEnabledAppID            forKey:NSPersistentStoreUbiquitousContentNameKey];
            [options setObject:iCloudLogsPath                forKey:NSPersistentStoreUbiquitousContentURLKey];

            [psc lock];

            [psc addPersistentStoreWithType:NSSQLiteStoreType 
                              configuration:nil 
                                        URL:[NSURL fileURLWithPath:iCloudData] 
                                    options:options 
                                      error:nil];

            [psc unlock];
        }
        else {
            NSLog(@"iCloud is NOT working - using a local store");
            NSLog(@"Local store: %@", localStore.path);
            NSMutableDictionary *options = [NSMutableDictionary dictionary];
            [options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
            [options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];

            [psc lock];

            [psc addPersistentStoreWithType:NSSQLiteStoreType 
                              configuration:nil 
                                        URL:localStore 
                                    options:options 
                                      error:nil];
            [psc unlock];

        }

        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"iCloud routine completed.");

            Setup *install = [[Setup alloc] init];

            if([install shouldMigrate]) {
                HUD = [[MBProgressHUD alloc] initWithView:self.window.rootViewController.view];
                HUD.delegate = self;
                HUD.labelText = NSLocalizedString(@"Sincronizzazione del database", nil);
                [self.window.rootViewController.view addSubview:HUD];
                [HUD showWhileExecuting:@selector(installDatabase) onTarget:install withObject:nil animated:YES];
            }
            else {
                [[NSNotificationCenter defaultCenter] postNotificationName:@"setupCompleted" object:self];
            }

            //[[NSNotificationCenter defaultCenter] postNotificationName:@"icloudCompleted" object:self userInfo:nil];
            [[NSNotificationCenter defaultCenter] postNotificationName:@"setupCompleted" object:self];
        });
    });

    return __persistentStoreCoordinator;
}
4

3 回答 3

0

在完成与 iCloud 的同步之前,您无法知道 iCloud 中是否有可用数据。这意味着您有两个选择:

  • 让用户等到同步完成。

  • 使用您的默认数据库启动并尽可能合并来自 iCloud 的更改。

使用 iCloud,您需要一些策略来解决本地数据和云数据之间的冲突,因为您必须处理用户可能同时更改多个设备上的数据的事实。一旦你有了它,很明显上面的第二个选项是更好的一个:用户可以立即开始使用你的应用程序,并且来自云的数据在可用时被合并。

于 2012-05-10T14:05:59.730 回答
0

我有完全相同的问题。

查看我的问题和我对它的回答iCloud + CoreData - 如何避免预先填充的数据重复?

实际上它不能100%正常工作。如果您敢于尝试,我可以向您解释如何使其 100% 正确工作(不过我还没有尝试过)。

考虑到您有大量数据要预先填充我的解决方案,现在可能适合您。

于 2012-05-11T06:52:48.043 回答
0

无法确定数据存储是否是第一次打开。至少不在 iCloud 核心数据存储上。想想看,iCloud 也应该离线工作——也就是说,当用户与 Internet 断开连接时,所有更改都应该被缓冲,然后在连接恢复时上传。如果不让用户等待几分钟(如果设备处于离线状态,甚至无限期地等待)来询问 iCloud 的数据副本,就无法检查数据存储是否已初始化。

要解决这个问题,您需要遵循以下四个简单的准则:

  • 有一种方法可以对预先填充的记录进行重复数据删除。
  • 有一种方法可以识别预先填充的记录并将其与用户输入的记录区分开来。
  • 每次从 iCloud 传入新的交易记录时,运行重复数据删除过程。
  • 每个设备/帐户组合仅种子数据记录一次。

您可以在此处阅读更多详细信息:http: //cutecoder.org/programming/seding-icloud-core-data/

于 2013-12-07T03:17:25.983 回答