Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 合并两个iOS核心数据持久存储的有效方法是什么?_Objective C_Core Data_Merge_Core Data Migration_Object Graph - Fatal编程技术网

Objective c 合并两个iOS核心数据持久存储的有效方法是什么?

Objective c 合并两个iOS核心数据持久存储的有效方法是什么?,objective-c,core-data,merge,core-data-migration,object-graph,Objective C,Core Data,Merge,Core Data Migration,Object Graph,在我们正在开发的应用程序中,我们使用核心数据和sqlite支持存储来存储我们的数据。我们应用程序的对象模型很复杂。此外,我们的应用程序提供的数据总量太大,无法装入iOS(iPhone/iPad/iPod Touch)应用程序包。由于我们的用户通常只对数据的一个子集感兴趣,因此我们对数据进行了分区,以便应用程序附带应用程序包中数据对象的一个子集(尽管约100 MB)。我们的用户在通过iTunes应用内购买支付额外内容后,可以选择从我们的服务器下载额外的数据对象(大小约5 MB到100 MB)。  

在我们正在开发的应用程序中,我们使用核心数据和sqlite支持存储来存储我们的数据。我们应用程序的对象模型很复杂。此外,我们的应用程序提供的数据总量太大,无法装入iOS(iPhone/iPad/iPod Touch)应用程序包。由于我们的用户通常只对数据的一个子集感兴趣,因此我们对数据进行了分区,以便应用程序附带应用程序包中数据对象的一个子集(尽管约100 MB)。我们的用户在通过iTunes应用内购买支付额外内容后,可以选择从我们的服务器下载额外的数据对象(大小约5 MB到100 MB)。   增量数据文件(存在于sqlite备份存储中)使用与捆绑包附带的数据相同的xcdatamodel版本;对象模型没有任何更改。增量数据文件作为gzip sqlite文件从我们的服务器下载。我们不想通过将增量内容与应用程序一起交付而使我们的应用程序包膨胀。此外,我们不希望依赖于webservice上的查询(因为复杂的数据模型)。   我们已经测试了从服务器下载的增量sqlite数据。我们已经能够将下载的数据存储添加到应用程序的共享persistentStoreCoordinator。

然而,这样做有两个问题

  • 数据获取结果(例如,使用NSFetchResultController)显示为 追加到数据结尾的incrementalStoreURL中的数据 来自defaultStoreURL的数据
  • 有些对象是重复的。有许多实体具有 数据模型中的只读数据;当我们添加时,这些将被复制 将第二个persistentStore发送给persistentStoreCoordinator
  • 理想情况下,我们希望核心数据将两个持久存储中的对象图合并为一个(在数据下载时,两个存储中的数据之间没有共享关系)。此外,我们希望删除重复的对象。 在网上搜索时,我们看到一些人提出了一些问题,他们试图做我们正在做的事情,比如和。我们已经读过了。然而,我们看到的所有解决方案都不适用于我们。我们不希望手动读取数据并将其从增量存储保存到默认存储,因为我们认为这在手机上非常缓慢且容易出错。有没有更有效的合并方法

    我们试图通过实现如下手动迁移来解决这个问题。但是,我们未能成功地实现合并。我们并不清楚上述答案1和答案2所建议的解决方案。Marcus Zarra的博客解决了我们在将大型数据集导入iOS项目开始时遇到的一些问题

    {
           NSError *error = nil;
           NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                                    [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, 
                                    [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];        
    
           NSMigrationManager *migrator = [[NSMigrationManager alloc] initWithSourceModel:__managedObjectModel destinationModel:__managedObjectModel];
           if (![migrator migrateStoreFromURL:stateStoreURL
                                    type:NSSQLiteStoreType 
                                 options:options 
                        withMappingModel:nil
                        toDestinationURL:destinationStoreURL 
                         destinationType:NSSQLiteStoreType 
                      destinationOptions:nil 
                                   error:&error])
           {
               NSLog(@"%@", [error userInfo]);
               abort();
           }
    }
    
    答案1的作者似乎最终从增量存储读取了数据,并保存到默认存储。也许,我们误解了第1条和第2条提出的解决方案。数据的大小可能使我们无法手动读取增量数据并将其重新插入默认存储。我的问题是:从两个persistentStore(具有相同的objectModel)获取对象图合并到一个persistentStore中的最有效方法是什么


    当我们向对象图添加新的实体属性或修改关系时,自动迁移效果非常好。有没有一个简单的解决方案可以将相似的数据合并到同一个持久存储中,这样就可以在自动迁移完成时,有足够的弹性停止并恢复

    迁移不起作用的原因是托管对象模型相同

    从技术上讲,您谈论的是“数据迁移”,而不是“模式迁移”。CoreData的迁移API设计用于模式迁移,即处理对托管对象模型的更改

    至于将数据从一家商店传输到另一家商店,你需要依靠自己。CoreData可以通过对获取请求使用批处理和获取限制来帮助您提高效率,但您需要自己实现逻辑

    听起来你有两个持久存储,一个大的和一个小的。加载较小的存储并对其进行分析,发现需要在较大的存储中查询的一组主键或唯一标识符,将是最有效的方法

    然后,只需在较大的存储中查询这些标识符,就可以轻松地消除重复

    NSFetchRequest的文档包含用于确定查询范围的API:


    您不需要任何迁移—迁移旨在改变NSManagedObjectModel,而不是数据本身

    您真正需要的是一个管理两个持久存储的持久存储协调器。这有点棘手,但不是太难,真的

    有一个类似的问题,可以解释你,你真正需要做什么。

    这是马库斯·扎拉写的一篇好文章


    经过几次尝试,我终于想出了如何使这项工作正常进行。秘密在于首先创建增量存储数据,而不为只读实体创建任何数据。在增量存储中不保留只读数据的情况下,这些实体实例的实体实例将在数据迁移和合并后被复制。因此,应在不使用这些只读实体的情况下创建增量存储。默认存储区将是唯一拥有它们的存储区

    例如,我的数据模型中有实体“国家”和“州”。我只需要在我的对象图中有一个Country和State实例。我将这些实体排除在增量存储之外,并仅在默认存储中创建它们。我使用获取的属性将我的主对象图松散地链接到这些实体。我使用模型中的所有实体实例创建了默认存储。增量存储要么没有只读实体(在我的例子中是国家和州),要么在数据创建完成后将其删除
    {
           NSError *error = nil;
           NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                                    [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, 
                                    [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];        
    
           NSMigrationManager *migrator = [[NSMigrationManager alloc] initWithSourceModel:__managedObjectModel destinationModel:__managedObjectModel];
           if (![migrator migrateStoreFromURL:stateStoreURL
                                    type:NSSQLiteStoreType 
                                 options:options 
                        withMappingModel:nil
                        toDestinationURL:destinationStoreURL 
                         destinationType:NSSQLiteStoreType 
                      destinationOptions:nil 
                                   error:&error])
           {
               NSLog(@"%@", [error userInfo]);
               abort();
           }
    }
    
    {
        NSError *error = nil;
        NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
        [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, 
        [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
    
        if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:defaultStoreURL options:options error:&error])
        {            
            NSLog(@"Failed with error:  %@", [error localizedDescription]);
            abort();
        }    
    
        // Check for the existence of incrementalStore
        // Add incrementalStore
        if (incrementalStoreExists) {
    
            NSPersistentStore *incrementalStore = [_incrementalPersistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:incrementalStoreURL options:options error:&error];
            if (!incrementalStore)
            {
                NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
                abort();
            }    
    
            if (![_incrementalPersistentStoreCoordinator migratePersistentStore:incrementalStore
                toURL:_defaultStoreURL
                options:options
                withType:NSSQLiteStoreType
                error:&error]) 
            {
                NSLog(@"%@", [error userInfo]);
                abort();
    
            }
    
            // Destroy the store and store coordinator for the incremental store
            [_incrementalPersistentStoreCoordinator removePersistentStore:incrementalStore error:&error];
            incrementalPersistentStoreCoordinator = nil;
            // Should probably delete the URL from file system as well
            //
        }
    }