3 回答
TA贡献1998条经验 获得超6个赞
我已经弄清楚了Apple在其文档中的提示。实际上,这很容易,但要走很长的路要走。我将通过一个示例来说明该解释。初始情况是这样的:
数据模型版本1
这是使用“带有核心数据存储的基于导航的应用程序”模板创建项目时获得的模型。我编译了它,并在for循环的帮助下进行了一些重创,以创建大约2k个条目,每个条目都有一些不同的值。在那里,我们以NSDate值进行了2.000个事件。
现在,我们添加数据模型的第二个版本,如下所示:
数据模型版本2
区别在于:事件实体不见了,我们有了两个新实体。一个将时间戳记存储为a double,第二个将时间戳记存储为NSString。
目标是将所有版本1事件转移到两个新实体,并在迁移过程中转换值。这将导致值的两倍,每个值在单独的实体中作为不同的类型。
要进行迁移,我们选择手动迁移,而映射模型就是这样做。这也是您问题答案的第一部分。我们将分两步进行迁移,因为迁移2k条目需要花费很长时间,并且我们希望保持较低的内存占用。
您甚至可以继续拆分这些映射模型,以仅迁移实体范围。假设我们有100万条记录,这可能会使整个过程崩溃。使用Filter谓词可以缩小获取的实体的范围。
回到我们的两个映射模型。
我们创建第一个映射模型,如下所示:
1.新建文件->资源->映射模型
2.选择一个名称,我选择了StepOne
3.设置源和目标数据模型
映射模型第一步
多遍迁移不需要自定义实体迁移策略,但是我们将为该示例提供更多细节。因此,我们向实体添加了自定义策略。这始终是的子类NSEntityMigrationPolicy。
该策略类实现了一些使迁移发生的方法。但是,在这种情况下很简单,因此我们只需要实现一种方法: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捆绑包结尾。
必须提供目标存储,并且不应将其作为源存储。成功迁移后,您可以删除旧的并重命名新的。
创建映射模型后,我对数据模型进行了一些更改,这导致了一些兼容性错误,我只能通过重新创建映射模型来解决。
TA贡献1835条经验 获得超7个赞
这些问题相关:
在iPhone上迁移大型CoreData数据存储时出现内存问题
iOS多通道核心数据迁移
引用第一个链接:
官方文档的“多次通过”部分对此进行了讨论,但是看起来他们建议的方法是按实体类型划分迁移,即制作多个映射模型,每个映射模型都从实体模型中迁移实体类型的子集。完整的数据模型。
- 3 回答
- 0 关注
- 587 浏览
添加回答
举报