将iCloud存储迁移到本地

时间:2014-02-12 15:03:55

标签: objective-c core-data ios7 icloud

迁移在Simulator上运行正常。但是在设备上,我看不到任何错误消息,但迁移的商店是空的。

NSDictionary *iCloudOptions = @{
    NSPersistentStoreUbiquitousContentNameKey : @"iCloudNimbleStore",
    NSPersistentStoreUbiquitousContentURLKey : @"transactions_logs",
    NSMigratePersistentStoresAutomaticallyOption : @YES,
    NSInferMappingModelAutomaticallyOption : @YES
};
NSDictionary *localOptions = @{NSMigratePersistentStoresAutomaticallyOption : @YES,
    NSInferMappingModelAutomaticallyOption : @YES
};
if (![[NSFileManager defaultManager]fileExistsAtPath:self.storeURL.path]) {
    @synchronized(@"Migration")
    {
        // thread-safe code
        if ([[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil]) {
            NSLog(@"iCloud");
            [self migrateStoreFromURL:[self nb_URLToStoreWithFilename:[self nb_appName]]options:iCloudOptions];
        }else{
            [self migrateStoreFromURL:[self nb_URLToStoreWithFilename:[NSString stringWithFormat:@"%@.sqlite", [self nb_appName]]] options:localOptions];
            //
            [self migrateStoreFromURL:[self nb_URLToOldStoreWithFilename] options:localOptions];
        }
    }
}

NSDictionary *options = @{
    NSMigratePersistentStoresAutomaticallyOption:@YES
    ,NSInferMappingModelAutomaticallyOption:@YES
};
NSError *error = nil;
[_coordinator lock];
_store = [_coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[self storeURL] options:options error:&error];
[_coordinator unlock];
if (!_store) {
    UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Loading Fail" message:[NSString stringWithFormat:@"Failed to add store. Error: %@", error] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
    [alert show];
    NSLog(@"Failed to add store. Error: %@", error);abort();
} else {
    UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Loading Success" message:[NSString stringWithFormat:@"Successfully added store: %@", _store] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
    [alert show];
    NSLog(@"Successfully added store: %@", _store);
    if (_store && !error) {
        // Encrypt the password database
        NSError *encrError;
        NSDictionary *fileAttributes = [NSDictionary dictionaryWithObject:NSFileProtectionComplete forKey:NSFileProtectionKey];
        if (![[NSFileManager defaultManager] setAttributes:fileAttributes ofItemAtPath:self.storeURL.path error:&encrError]){
            NSLog(@"Unresolved error with password store encryption %@, %@", encrError, [encrError userInfo]); 
            abort();
        }else {NSLog(@"Encrypted");}
    }
}

以下是迁移程序:

- (void)migrateStoreFromURL:(NSURL *)oldStoreURL options:(NSDictionary *)oldOptions{
if (debug==1) {
    TFLog(@"Running %@ '%@'", self.class, NSStringFromSelector(_cmd));
}
if (_store)
{
    NSLog(@"NOT NEEDED");
    return;
}

UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Migration" message:[NSString stringWithFormat:@"Found old store at %@",oldStoreURL.path] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
[alert show];

NSFileManager *fileManager = [NSFileManager defaultManager];

if (![fileManager fileExistsAtPath:self.storeURL.path]) {
    NSDictionary *options =
    @{
      NSMigratePersistentStoresAutomaticallyOption:@YES
      ,NSInferMappingModelAutomaticallyOption:@YES
      };
    NSError *error = nil;
    [_coordinator lock];
    NSPersistentStore *srcPS = [_coordinator addPersistentStoreWithType:NSSQLiteStoreType
                                                                                  configuration:nil
                                                                                            URL:oldStoreURL
                                                                                        options:oldOptions
                                                                                          error:&error];

    _store = [_coordinator migratePersistentStore:srcPS
                                                                             toURL:self.storeURL
                                                                           options:options
                                                                          withType:NSSQLiteStoreType
                                                                             error:&error];
    [_coordinator unlock];
    if (_store && !error) {
        UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Migration Success" message:[NSString stringWithFormat:@"Old store successfully migrated from %@",oldStoreURL.path] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
        [alert show];
        // Encrypt the password database
        NSError *encrError;
        NSDictionary *fileAttributes = [NSDictionary dictionaryWithObject:NSFileProtectionComplete forKey:NSFileProtectionKey];
        if (![[NSFileManager defaultManager] setAttributes:fileAttributes ofItemAtPath:self.storeURL.path error:&encrError]){
            UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Encryption Error" message:[NSString stringWithFormat:@"Unresolved error with password store encryption %@, %@", encrError, [encrError userInfo]] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
            [alert show];
        }

    }else{
        UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Migration Error" message:error.localizedDescription delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
        [alert show];
    }

}

更新。:我检查了新迁移的商店的大小,它是0.最奇怪的是_store && !error是真的。我还尝试将NSPersistentStoreRemoveUbiquitousMetadataOption: @YES添加到迁移选项中,但它不会改变任何内容。

UPD。 2 我认为在设备上iCloud存储url在加载之前是零。我需要一些解决方法,等到它完成。

1 个答案:

答案 0 :(得分:1)

我不是100%确定我理解你要对迁移做些什么。通常使用迁移在空白商店中播种数据,但看起来您正试图将数据从iCloud迁移到本地商店。是对的吗?你不应该这样做。 iCloud应自动将其他设备的数据添加到您的商店。

这条线看起来也不正确:

NSPersistentStoreUbiquitousContentURLKey : @"transactions_logs",

我认为你想在那里使用指向iCloud容器内的事务日志目录的URL。例如

NSURL *containerURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
NSURL *url = [containerURL URLByAppendingPathComponent:@"transactions_logs"];

使用iCloud时,重要的是要意识到数据不会即时传输。它可能需要一段时间才能到达,您的应用程序确实没有任何方法可以确定是否有数据到来。您可以使用元数据查询来监控元数据,但即使这样也经常在其他设备上的数据生成后的某个时间到达。

因此,简单地在无处不在的容器中查找数据将无济于事,因为可能存在数据,也可能没有。你只是不知道,你必须考虑到这个假设来开发你的方法,以便它可以处理任何延迟。

使iCloud同步与Core Data一起使用所需的迁移非常麻烦且不必要。您可能更有可能使用自动执行该操作的框架(例如Core Data Ensembles)使事情运行良好。 (披露:我是Ensembles的开发者。)