前一段时间遇到了一些Core Data数据迁移方面的问题,学到了不少东西。于是就总结了一下写了一个Core Data数据迁移的类,也写了一篇博客如何运用更聪明的办法进行Core Data数据迁移,希望能帮助那些对Core Data数据库迁移有疑问的同志们少走一些弯路吧。
这个类使用起来很简单,只有很少的接口暴露出来
- 判断当前的数据库模型是否和最终的数据模型有冲突
// 判断数据库版本是否有兼容问题,我这里用的是MagicalRecord
NSURL *finalStoreURL = [NSPersistentStore MR_urlForStoreName:[MagicalRecord defaultStoreName]];
NSManagedObjectModel *defaultMOM = [NSManagedObjectModel MR_defaultManagedObjectModel];
WYZCoreDataMigrationManager *migrationManager = [[WYZCoreDataMigrationManager alloc] init];
BOOL isNeedMigration = [migrationManager isMigrationNeededForModel:defaultMOM storeURL:finalStoreURL];
- 如果没有冲突直接加载UI,否则进行数据库迁移、合并:
if (isNeedMigration) {
// 升级期间禁止自动锁屏
[UIApplication sharedApplication].idleTimerDisabled = YES;
// 将升级过程放入后台执行代码,防止用户按了home键之后进程被系统杀死
__block UIBackgroundTaskIdentifier bgTask;
bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
// 这里可以提示正在升级
migrationManager.delegate = self;
NSError *error = nil;
NSInteger maxTry = 3;
NSInteger currentTry = 1;
BOOL isMigrationSuccess = NO;
while (!isMigrationSuccess && currentTry <= maxTry) {
isMigrationSuccess = [migrationManager progressivelyMigrateURL:finalStoreURL toModel:defaultMOM error:&error];
if (!isMigrationSuccess) {
currentTry++;
}
}
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
[NSThread sleepForTimeInterval:0.5];
[UIApplication sharedApplication].idleTimerDisabled = NO;
});
}
- 实现delegate方法,更新进度
- (void)migrationManager:(WYZCoreDataMigrationManager *)manager withProgress:(CGFloat)progress {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"当前完成:%.2f%%", progress * 100);
});
}
- 升级过程不能放在入口函数并用同步线程,如果是数据量较大的重量级迁移,则可能由于入口函数超过一定时间没有返回YES/NO而导致应用进程被系统杀死。我的做法是先返回YES/NO,Core Data在异步线程进行数据迁移,前已完成之后发送通知,应用收到通知后再加载UI。
- 各个版本数据库模型的versionIdentifiers要填写,其值为版本的序列,比如第一个版本为1,第二个版本为2等……,这样是为了方便WYZCoreDataMigrationManager找到当前数据库模型的下一个版本
- 尽量将mapping model拆分成多个以节约内存开销,并且确保每个mapping model中的entity是于其他mapping model是没有任何关系的(否则编译时会报错)