Jas*_*son 85 iphone core-data objective-c core-data-migration ios
我的iPhone应用程序需要迁移其核心数据存储,而且一些数据库非常庞大.Apple的文档建议使用"多次传递"来迁移数据以减少内存使用.但是,文档非常有限,并没有很好地解释如何实际执行此操作.有人可以指出我一个好的例子,或者详细解释如何实际解决这个问题的过程吗?
Nic*_*ver 172
我已经弄明白了Apple在他们的文档中暗示了什么.它实际上非常简单,但在它显而易见之前还有很长的路要走.我将用一个例子说明解释.最初的情况是这样的:

这是使用"基于导航的应用程序和核心数据存储"模板创建项目时获得的模型.我编译了它,并在for循环的帮助下做了一些努力,创建了大约2k个条目,所有条目都有一些不同的值.我们用NSDate值去了2000个事件.
现在我们添加第二个版本的数据模型,如下所示:

区别在于:Event实体已经消失,我们有两个新的实体.一个存储时间戳作为a double和第二个应存储日期的时间戳NSString.
目标是将所有版本1事件传输到两个新实体,并在迁移过程中转换值.这导致两个值作为单独的权利中的不同类型的两倍.
要进行迁移,我们选择手动迁移,我们使用映射模型.这也是你问题答案的第一部分.我们将分两步进行迁移,因为迁移2k条目需要很长时间,我们希望保持较低的内存占用.
您甚至可以继续拆分这些映射模型,以仅迁移实体的范围.假设我们有一百万条记录,这可能会导致整个过程崩溃.可以使用Filter谓词缩小获取的实体的范围.
我们创建第一个这样的映射模型:
1.新文件 - >资源 - >映射模型

2.选择一个名字,我选择了StepOne
3.设置源和目标数据模型




多次传递迁移不需要自定义实体迁移策略,但是我们将这样做以获得此示例的更多详细信息.因此,我们向实体添加自定义策略.这始终是子类NSEntityMigrationPolicy.

此策略类实现了一些方法来实现迁移.但是在这种情况下它很简单,所以我们只需要实现一种方法:createDestinationInstancesForSourceInstance:entityMapping:manager:error:.
实现将如下所示:
#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;
}
Run Code Online (Sandbox Code Playgroud)
我将跳过设置第二个映射模型的部分,它几乎完全相同,只是用于将NSDate转换为double的timeIntervalSince1970.
最后,我们需要触发迁移.我暂时跳过样板代码.如果您需要,我会在这里发布.它可以在Customizing the Migration Process中找到,它只是前两个代码示例的合并.如下第三和最后一部分将被修改:除了使用的类方法的NSMappingModel类mappingModelFromBundles:forSourceModel:destinationModel:,我们会使用initWithContentsOfURL:,因为该类方法将返回只有一个,也许是第一次,发现映射模型的捆绑.
现在我们有了两个映射模型,可以在lopp的每次传递中使用,并将migrate方法发送到迁移管理器.而已.
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];
}
Run Code Online (Sandbox Code Playgroud)
笔记
映射模型以cdm捆绑结束.
必须提供目标存储,不应该是源存储.成功迁移后,您可以删除旧版本并重命名新版本.
在创建映射模型后,我对数据模型进行了一些更改,这导致了一些兼容性错误,我只能通过重新创建映射模型来解决这些问题.