iOS CoreData数据迁移-迁移管理器迁移数据

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010123208/article/details/50802117

我们在开发或者产品升级的时候经常会遇到托管模型的结构化修改(也就是表的结构改变),那么我们就需要数据迁移到新的模型中。

  1. 轻量级迁移方式
  2. 默认的迁移方式
  3. 迁移管理器迁移方式

现在记录一下最后一种迁移方式,迁移管理器迁移数据。

大家有没有这样的体验,就是升级新版QQ的时候,第一次开启会首先要导入原来数据。 会有导入的进度条。对当数据迁移量很大的时候就需要花费较长的时间。为了更好的用户体验,我们需要让用户知道已经迁移多少,还有多少。这样不至于让用户无目标的等待,或者不耐烦的关闭。 迁移管理器就为我们提供了,迁移进度值。

首先我们先下载操作底板:下载

下载完成后,运行一下程序,插入数据。
如果程序出现崩溃请参考前两篇文章进行处理。(删除原有数据库文件,或者clean一下)。

首先我们添加Model版本
这里写图片描述
这里写图片描述
这里写图片描述
然后设置当前运行版本
这里写图片描述
然后我们就可以操作新的实体了,可以直接删除,新建一个实体,或者修改现在的实体。
我们删除掉重新创建 Entity2
这里写图片描述
好创建好新的实体后,我们来创建映射模型。
这里写图片描述
这里写图片描述
这里写图片描述
创建完成后我们来设置一下
这里写图片描述
完成映射模型

当进行迁移的时候我们需要判断一下是否需要迁移,是否已经迁移过了。
也就是比较原有的存储模型是否与现在的存储模型相同。

-(BOOL)isMigrationNecessaryForStore:(NSURL *)storeURL
{
    //是否存在文件,如果不存在直接返回NO
    if (![[NSFileManager defaultManager] fileExistsAtPath:[self storeURL].path]) {
        return NO;
    }
    NSError *error = nil;

    //比较存错模型的元数据。
    NSDictionary *sourceMataData = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType URL:storeURL error:&error];
    NSManagedObjectModel *destinationModel = _coordinator.managedObjectModel;
    if ([destinationModel isConfiguration:nil compatibleWithStoreMetadata:sourceMataData]) {
        return NO;
    }
    return YES;

}

下面开始数据迁移

-(BOOL)migrateStore:(NSURL *)sourceStore
{
    BOOL successs = NO;
    NSError *error = nil;


    //原来的数据模型的原信息
    NSDictionary *sourceMetadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType
                                                                                              URL:sourceStore
                                                                                            error:&error];
    //原数据模型
    NSManagedObjectModel *sourceModel = [NSManagedObjectModel mergedModelFromBundles:nil forStoreMetadata:sourceMetadata];

    //最新版数据模型
    NSManagedObjectModel *destinModel = _model;

    //数据迁移的映射模型
    NSMappingModel *mappingModel = [NSMappingModel mappingModelFromBundles:nil
                                                            forSourceModel:sourceModel
                                                          destinationModel:destinModel];
    if (mappingModel) {
        NSError *error = nil;

        //迁移管理器
        NSMigrationManager *migrationManager = [[NSMigrationManager alloc]initWithSourceModel:sourceModel
                                                                             destinationModel:destinModel];

        //这里可以注册监听  NSMigrationManager 的 migrationProgress来查看进度

        //先把模型存错到Temp.sqlite
        NSURL *destinStore = [[self applictaionStoresDirectory] URLByAppendingPathComponent:@"Temp.sqlite"];
        successs = [migrationManager migrateStoreFromURL:sourceStore
                                                    type:NSSQLiteStoreType
                                                 options:nil
                                        withMappingModel:mappingModel
                                        toDestinationURL:destinStore
                                         destinationType:NSSQLiteStoreType
                                      destinationOptions:nil
                                                   error:&error];
        if (successs) {
            //成功后替换掉原来的旧的文件
            if ([self replaceStore:sourceStore withStore:destinStore]) {
//                这里移除监听就可以了。
            }
        }
    }
    return successs;
}

文件替换

-(BOOL) replaceStore:(NSURL *)old withStore:(NSURL *)new
{
    BOOL success = NO;
    NSError *error = nil;
    if ([[NSFileManager defaultManager] removeItemAtURL:old error:&error]) {
        error = nil;
        if ([[NSFileManager defaultManager] moveItemAtURL:new toURL:old error:&error]) {
            success = YES;
        }
    }
    return success;
}

现在基本已经基本完成。我们在导入数据模型的时候来判断是否需要数据迁移,那么我们需要在CoreDataHelper.m文件中的loadStore方法中添加。

-(void)loadStore
{
    if (_store) {
        return ;
    }

    BOOL useMigrationManager = YES;
    if (useMigrationManager &&[self isMigrationNecessaryForStore:[self storeURL]]) {
        [self migrateStore:[self storeURL]];
    }else{
        NSError *error;

        NSDictionary *options = @{NSMigratePersistentStoresAutomaticallyOption:@(YES),
                                  NSInferMappingModelAutomaticallyOption:@(NO)};
        _store =[_coordinator addPersistentStoreWithType:NSSQLiteStoreType
                                           configuration:nil
                                                     URL:[self storeURL]
                                                 options:options
                                                   error:&error];
        if (!_store) {
            abort();
        }
    }

}

我们来看看是否成功了。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.

    NSLog(@"%@",NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES));
    _coreDataHelper = [[CoreDataHelper alloc]init];//初始化
    [_coreDataHelper setupCoreData];//设置持久化对象存储
    NSManagedObjectContext *context = _coreDataHelper.managedContext;
//    
//    for (NSInteger i = 0; i<100000; i++) {
//        Entity1 *entity = [NSEntityDescription insertNewObjectForEntityForName:@"Entity1" inManagedObjectContext:context];
//        entity.name = [NSString stringWithFormat:@"name%ld",i];
//        entity.age = @(i);
//    }

    NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Entity2" inManagedObjectContext:context];
    NSFetchRequest *request = [[NSFetchRequest alloc]init];
    request.entity = entityDescription;

    NSArray *array = [context executeFetchRequest:request error:nil];
    for (Entity2 *entity in array) {
        NSLog(@"name2:%@,age2:%@",entity.name2,entity.age2);
    }
    [_coreDataHelper saveContext];
//

    return YES;
}

这里写图片描述
好的,来运行程序 数据迁移成功了。

阅读更多
换一批

没有更多推荐了,返回首页