为了账号安全,请及时绑定邮箱和手机立即绑定

多次通过核心数据迁移的示例或说明?

多次通过核心数据迁移的示例或说明?

浮云间 2019-10-14 11:19:51
我的iPhone应用程序需要迁移其核心数据存储,并且某些数据库非常大。苹果的文档建议使用“多次通过”来迁移数据以减少内存使用。但是,文档非常有限,并且不能很好地说明如何实际执行此操作。有人可以为我指出一个好的例子,还是详细说明如何真正实现这一目标的过程?
查看完整描述

3 回答

?
米琪卡哇伊

TA贡献1998条经验 获得超6个赞

我已经弄清楚了Apple在其文档中的提示。实际上,这很容易,但要走很长的路要走。我将通过一个示例来说明该解释。初始情况是这样的:


数据模型版本1

//img1.sycdn.imooc.com//5da3e9970001be4801510084.jpg//img1.sycdn.imooc.com//5da3e9970001703b04570064.jpg


这是使用“带有核心数据存储的基于导航的应用程序”模板创建项目时获得的模型。我编译了它,并在for循环的帮助下进行了一些重创,以创建大约2k个条目,每个条目都有一些不同的值。在那里,我们以NSDate值进行了2.000个事件。


现在,我们添加数据模型的第二个版本,如下所示:


//img1.sycdn.imooc.com//5da3e99b0001d8fd03020086.jpg

数据模型版本2

区别在于:事件实体不见了,我们有了两个新实体。一个将时间戳记存储为a double,第二个将时间戳记存储为NSString。


目标是将所有版本1事件转移到两个新实体,并在迁移过程中转换值。这将导致值的两倍,每个值在单独的实体中作为不同的类型。


要进行迁移,我们选择手动迁移,而映射模型就是这样做。这也是您问题答案的第一部分。我们将分两步进行迁移,因为迁移2k条目需要花费很长时间,并且我们希望保持较低的内存占用。


您甚至可以继续拆分这些映射模型,以仅迁移实体范围。假设我们有100万条记录,这可能会使整个过程崩溃。使用Filter谓词可以缩小获取的实体的范围。


回到我们的两个映射模型。

我们创建第一个映射模型,如下所示:


1.新建文件->资源->映射模型 

//img1.sycdn.imooc.com//5da3e9ad0001dcf206800596.jpg

2.选择一个名称,我选择了StepOne


3.设置源和目标数据模型


//img1.sycdn.imooc.com//5da3e9b40001617605930550.jpg


映射模型第一步

//img1.sycdn.imooc.com//5da3e9b90001f99903340057.jpg

//img1.sycdn.imooc.com//5da3e9ba0001d07603630070.jpg

//img1.sycdn.imooc.com//5da3e9bb00013e5202910066.jpg


多遍迁移不需要自定义实体迁移策略,但是我们将为该示例提供更多细节。因此,我们向实体添加了自定义策略。这始终是的子类NSEntityMigrationPolicy。

//img1.sycdn.imooc.com//5da3e9be0001be3003580246.jpg


该策略类实现了一些使迁移发生的方法。但是,在这种情况下很简单,因此我们只需要实现一种方法:createDestinationInstancesForSourceInstance:entityMapping:manager:error:。


该实现将如下所示:


StepOneEntityMigrationPolicy.m

#import "StepOneEntityMigrationPolicy.h"



@implementation StepOneEntityMigrationPolicy


- (BOOL)createDestinationInstancesForSourceInstance:(NSManagedObject *)sInstance 

                                      entityMapping:(NSEntityMapping *)mapping 

                                            manager:(NSMigrationManager *)manager 

                                              error:(NSError **)error

{

    // Create a new object for the model context

    NSManagedObject *newObject = 

        [NSEntityDescription insertNewObjectForEntityForName:[mapping destinationEntityName] 

                                      inManagedObjectContext:[manager destinationContext]];


    // do our transfer of nsdate to nsstring

    NSDate *date = [sInstance valueForKey:@"timeStamp"];

    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];

    [dateFormatter setTimeStyle:NSDateFormatterMediumStyle];

    [dateFormatter setDateStyle:NSDateFormatterMediumStyle];    


    // set the value for our new object

    [newObject setValue:[dateFormatter stringFromDate:date] forKey:@"printedDate"];

    [dateFormatter release];


    // do the coupling of old and new

    [manager associateSourceInstance:sInstance withDestinationInstance:newObject forEntityMapping:mapping];


    return YES;

}

最后一步:迁移本身

我将跳过设置几乎完全相同的第二个映射模型的部分,只是将NSDate转换为double的timeIntervalSince1970。


最后,我们需要触发迁移。我现在暂时跳过样板代码。如果您需要,我会在这里发布。可以在“ 定制迁移过程”中找到它,它只是前两个代码示例的合并。如下第三和最后一部分将被修改:除了使用的类方法的NSMappingModel类mappingModelFromBundles:forSourceModel:destinationModel:,我们会使用initWithContentsOfURL:,因为该类方法将返回只有一个,也许是第一次,发现映射模型的捆绑。


现在,我们有了两个映射模型,它们可以在循环的每个过程中使用,并将迁移方法发送到迁移管理器。而已。


NSArray *mappingModelNames = [NSArray arrayWithObjects:@"StepOne", @"StepTwo", nil];

NSDictionary *sourceStoreOptions = nil;


NSURL *destinationStoreURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"CoreDataMigrationNew.sqlite"];


NSString *destinationStoreType = NSSQLiteStoreType;


NSDictionary *destinationStoreOptions = nil;


for (NSString *mappingModelName in mappingModelNames) {

    NSURL *fileURL = [[NSBundle mainBundle] URLForResource:mappingModelName withExtension:@"cdm"];


    NSMappingModel *mappingModel = [[NSMappingModel alloc] initWithContentsOfURL:fileURL];


    BOOL ok = [migrationManager migrateStoreFromURL:sourceStoreURL

                                               type:sourceStoreType

                                            options:sourceStoreOptions

                                   withMappingModel:mappingModel

                                   toDestinationURL:destinationStoreURL

                                    destinationType:destinationStoreType

                                 destinationOptions:destinationStoreOptions

                                              error:&error2];

    [mappingModel release];

笔记


映射模型以cdm捆绑包结尾。


必须提供目标存储,并且不应将其作为源存储。成功迁移后,您可以删除旧的并重命名新的。


创建映射模型后,我对数据模型进行了一些更改,这导致了一些兼容性错误,我只能通过重新创建映射模型来解决。


查看完整回答
反对 回复 2019-10-14
?
qq_花开花谢_0

TA贡献1835条经验 获得超7个赞

这些问题相关:


在iPhone上迁移大型CoreData数据存储时出现内存问题


iOS多通道核心数据迁移


引用第一个链接:


官方文档的“多次通过”部分对此进行了讨论,但是看起来他们建议的方法是按实体类型划分迁移,即制作多个映射模型,每个映射模型都从实体模型中迁移实体类型的子集。完整的数据模型。


查看完整回答
反对 回复 2019-10-14
  • 3 回答
  • 0 关注
  • 587 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信