核心数据“自动轻量级移植”的实现(iPhone)

时间:2022-07-31 00:22:28

I would like to make my app able to do an automatic lightweight migration when I add new attributes to my core data model.

当我向核心数据模型添加新属性时,我想让我的应用程序能够进行自动轻量级迁移。

In the guide from Apple this is the only info on the subject I could find:

在苹果的指南中,这是我能找到的关于这个主题的唯一信息:

Automatic Lightweight Migration

自动轻量级迁移

To request automatic lightweight migration, you set appropriate flags in the options dictionary you pass in addPersistentStoreWithType:configuration:URL:options:error:. You need to set values corresponding to both the NSMigratePersistentStoresAutomaticallyOption and the NSInferMappingModelAutomaticallyOption keys to YES:

要请求自动轻量级迁移,您需要在传入addPersistentStoreWithType:configuration:URL:options:error:的options字典中设置适当的标志。您需要设置与NSMigratePersistentStoresAutomaticallyOption和NSInferMappingModelAutomaticallyOption键对应的值为YES:

NSError *error;
NSURL *storeURL = <#The URL of a persistent store#>;
NSPersistentStoreCoordinator *psc = <#The coordinator#>;
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
    [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
    [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

if (![psc addPersistentStoreWithType:<#Store type#>
    configuration:<#Configuration or nil#> URL:storeURL
    options:options error:&error]) {
    // Handle the error.
}

My NSPersistentStoreCoordinator is initialized in this way:

我的NSPersistentStoreCoordinator是这样初始化的:

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

    if (persistentStoreCoordinator != nil) {
        return persistentStoreCoordinator;
    }

    NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"FC.sqlite"]];

    NSError *error = nil;
    persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error]) {

        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }    

    return persistentStoreCoordinator;
}

I am having trouble seeing where and how I should add the Apple code to get the Automatic Lightweight Migration working?

我不知道应该在何处以及如何添加Apple代码以使自动轻量级移植工作?

5 个解决方案

#1


93  

This is what I did to make Automatic Lightweight Migration (Source: http://brainwashinc.wordpress.com/2010/01/18/iphone-coredata-automatic-light-migration/)

这就是我做的自动轻量级迁移(来源:http://brainwashinc.wordpress.com/2010/01/18/iphone-coredata- automaticlight -migration/)

1. Set the Persistent Store options for automatic migration in the app delegate.

Change your persistentStoreCoordinator creation to this (replace YOURDB):

将您的persistentStoreCoordinator创建更改为这个(替换您的db):

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

  if (persistentStoreCoordinator != nil) {
    return persistentStoreCoordinator;
  }

  NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"YOURDB.sqlite"]];

  // handle db upgrade
  NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
  [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
  [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

  NSError *error = nil;
  persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
  if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {
    // Handle error
  }

  return persistentStoreCoordinator;
}

2. Version your Data Model and Edit the new file.

Select your xcdatamodel file Design -> Data Model -> Add Model Version (expand your xcdatamodeld item) Select the “2″ (or later) file, Design -> Data Model -> Set Current Version (edit this version)

选择您的xcdatamodel文件设计—>数据模型—>添加模型版本(扩展您的xcdatamodeld项目)选择“2”(或稍后)文件,设计—>数据模型—>设置当前版本(编辑此版本)

3. Specify the momd resource in app delegate.

Change your managedObjectModel implementation to this (replace YOURDB)

将managedObjectModel实现更改为这个(替换YOURDB)

- (NSManagedObjectModel *)managedObjectModel {

  if (managedObjectModel != nil) {
    return managedObjectModel;
  }

  NSString *path = [[NSBundle mainBundle] pathForResource:@"YOURDB" ofType:@"momd"];
  NSURL *momURL = [NSURL fileURLWithPath:path];
  managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:momURL];

  return managedObjectModel;
}

#2


7  

At first, the above solution didn't work for me. The returned managedObjectModel was 0x0. I think this is because I renamed the file names of the different model files. If you follow the instructions above to the letter then it all works.

起初,上面的解决方案对我不起作用。返回的managedObjectModel是0x0。我认为这是因为我重新命名了不同模型文件的文件名。如果你按照上面的说明写这封信,一切都可以。

However if you do change model file names then you can select the "current" model file manually: Lets say your original model file was MYMODEL.xcdatamodel after doing the add model step above this turns into a directory MY.xcdatamodeld and below it you have MYMODEL.xcdatamodel and MYMODEL 2.xcdatamodel rename the new model file to whatever you want, for example lets say you removed the space to MYMODEL2.xcdatamodel and edit its content. Now in the above code do

但是,如果您确实更改了模型文件名,那么您可以手动选择“当前”模型文件:假设您的原始模型文件是MYMODEL。在完成上面的添加模型步骤之后,xcdatamodel将其转换为一个目录MY。xcdatamodeld下面是MYMODEL。xcdatamodel MYMODEL 2。xcdatamodel将新模型文件重命名为您想要的任何文件,例如,假设您将空间删除为MYMODEL2。xcdatamodel编辑它的内容。在上面的代码中

NSString *path = [mainBundle pathForResource:@"MYMODEL2" ofType:@"mom" inDirectory:@"MYMODEL.momd"];

#3


1  

I think this adds onto the last answer.

我认为这是最后一个答案。

I found the usage of the bundle resource and .sqlite names really confusing at first. Does the bundle resource name change with the version change? Does the .sqlite name change? I've now got my migration working, and learned that the bundle model name refers to the name of the directory/folder in XCode containing all the models, not the name of the model versions within that directory.

首先,我发现了bundle资源和.sqlite名称的用法。包资源名称是否随版本更改而改变?.sqlite名称更改了吗?现在,我已经开始迁移,并了解到bundle模型名引用包含所有模型的XCode中的目录/文件夹的名称,而不是该目录中的模型版本的名称。

When you give a modelResource name to:

当您提供一个modelResource名称时:

NSURL *modelURL = [[NSBundle mainBundle] URLForResource:modelResource withExtension:@"momd"];
NSManagedObjectModel *theManagedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];

That modelResource name is the directory/folder for the models in Xcode.

该模型资源名是Xcode中模型的目录/文件夹。

When you do:

当你做的事:

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:storeFileName];
    NSError *error = nil;

    if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
        // handle error
    }

The storeFileName is the name of your .sqlite file in the Documents folder/directory (this is not in the bundle).

storeFileName是document文件夹/目录中.sqlite文件的名称(不在bundle中)。

Also, when you migrate from one model version to another model version, by default, the .sqlite file name remains the same.

此外,当您从一个模型版本迁移到另一个模型版本时,默认情况下.sqlite文件名保持不变。

#4


0  

Oscar, in response to your issue, I found the same thing initially. I would suggest deleting and re-adding the new .xcdatamodeld file to your project, and then rebuilding. Hope that helps!

奥斯卡,在回答你的问题时,我一开始也发现了同样的问题。我建议删除并重新添加新的.xcdatamodeld文件到您的项目中,然后重新构建。希望会有帮助!

#5


0  

Swift 3 Solution

斯威夫特3解决方案

1. Set the Persistent Store options for automatic migration in the app delegate.

1。设置应用程序委托中自动迁移的持久存储选项。

Change your persistentStoreCoordinator creation to this (replace SingleViewCoreData.sqlite):

将您的persistentStoreCoordinator创建更改为这个(替换SingleViewCoreData.sqlite):

lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {


let coordinator: NSPersistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.appendingPathComponent("SingleViewCoreData.sqlite")

let options = [
  NSMigratePersistentStoresAutomaticallyOption : Int(true),
  NSInferMappingModelAutomaticallyOption : Int(true)
]

do {

  try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: options)

} catch {

  print(error)
}

return coordinator

}()

2. Version your Data Model and Edit the new file.

2。修改数据模型并编辑新文件。

Select your xcdatamodel file Editor>Add Model Version - add a name for your new model

选择您的xcdatamodel文件编辑器>添加模型版本——为您的新模型添加一个名称

#1


93  

This is what I did to make Automatic Lightweight Migration (Source: http://brainwashinc.wordpress.com/2010/01/18/iphone-coredata-automatic-light-migration/)

这就是我做的自动轻量级迁移(来源:http://brainwashinc.wordpress.com/2010/01/18/iphone-coredata- automaticlight -migration/)

1. Set the Persistent Store options for automatic migration in the app delegate.

Change your persistentStoreCoordinator creation to this (replace YOURDB):

将您的persistentStoreCoordinator创建更改为这个(替换您的db):

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

  if (persistentStoreCoordinator != nil) {
    return persistentStoreCoordinator;
  }

  NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"YOURDB.sqlite"]];

  // handle db upgrade
  NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
  [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
  [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

  NSError *error = nil;
  persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
  if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {
    // Handle error
  }

  return persistentStoreCoordinator;
}

2. Version your Data Model and Edit the new file.

Select your xcdatamodel file Design -> Data Model -> Add Model Version (expand your xcdatamodeld item) Select the “2″ (or later) file, Design -> Data Model -> Set Current Version (edit this version)

选择您的xcdatamodel文件设计—>数据模型—>添加模型版本(扩展您的xcdatamodeld项目)选择“2”(或稍后)文件,设计—>数据模型—>设置当前版本(编辑此版本)

3. Specify the momd resource in app delegate.

Change your managedObjectModel implementation to this (replace YOURDB)

将managedObjectModel实现更改为这个(替换YOURDB)

- (NSManagedObjectModel *)managedObjectModel {

  if (managedObjectModel != nil) {
    return managedObjectModel;
  }

  NSString *path = [[NSBundle mainBundle] pathForResource:@"YOURDB" ofType:@"momd"];
  NSURL *momURL = [NSURL fileURLWithPath:path];
  managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:momURL];

  return managedObjectModel;
}

#2


7  

At first, the above solution didn't work for me. The returned managedObjectModel was 0x0. I think this is because I renamed the file names of the different model files. If you follow the instructions above to the letter then it all works.

起初,上面的解决方案对我不起作用。返回的managedObjectModel是0x0。我认为这是因为我重新命名了不同模型文件的文件名。如果你按照上面的说明写这封信,一切都可以。

However if you do change model file names then you can select the "current" model file manually: Lets say your original model file was MYMODEL.xcdatamodel after doing the add model step above this turns into a directory MY.xcdatamodeld and below it you have MYMODEL.xcdatamodel and MYMODEL 2.xcdatamodel rename the new model file to whatever you want, for example lets say you removed the space to MYMODEL2.xcdatamodel and edit its content. Now in the above code do

但是,如果您确实更改了模型文件名,那么您可以手动选择“当前”模型文件:假设您的原始模型文件是MYMODEL。在完成上面的添加模型步骤之后,xcdatamodel将其转换为一个目录MY。xcdatamodeld下面是MYMODEL。xcdatamodel MYMODEL 2。xcdatamodel将新模型文件重命名为您想要的任何文件,例如,假设您将空间删除为MYMODEL2。xcdatamodel编辑它的内容。在上面的代码中

NSString *path = [mainBundle pathForResource:@"MYMODEL2" ofType:@"mom" inDirectory:@"MYMODEL.momd"];

#3


1  

I think this adds onto the last answer.

我认为这是最后一个答案。

I found the usage of the bundle resource and .sqlite names really confusing at first. Does the bundle resource name change with the version change? Does the .sqlite name change? I've now got my migration working, and learned that the bundle model name refers to the name of the directory/folder in XCode containing all the models, not the name of the model versions within that directory.

首先,我发现了bundle资源和.sqlite名称的用法。包资源名称是否随版本更改而改变?.sqlite名称更改了吗?现在,我已经开始迁移,并了解到bundle模型名引用包含所有模型的XCode中的目录/文件夹的名称,而不是该目录中的模型版本的名称。

When you give a modelResource name to:

当您提供一个modelResource名称时:

NSURL *modelURL = [[NSBundle mainBundle] URLForResource:modelResource withExtension:@"momd"];
NSManagedObjectModel *theManagedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];

That modelResource name is the directory/folder for the models in Xcode.

该模型资源名是Xcode中模型的目录/文件夹。

When you do:

当你做的事:

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:storeFileName];
    NSError *error = nil;

    if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
        // handle error
    }

The storeFileName is the name of your .sqlite file in the Documents folder/directory (this is not in the bundle).

storeFileName是document文件夹/目录中.sqlite文件的名称(不在bundle中)。

Also, when you migrate from one model version to another model version, by default, the .sqlite file name remains the same.

此外,当您从一个模型版本迁移到另一个模型版本时,默认情况下.sqlite文件名保持不变。

#4


0  

Oscar, in response to your issue, I found the same thing initially. I would suggest deleting and re-adding the new .xcdatamodeld file to your project, and then rebuilding. Hope that helps!

奥斯卡,在回答你的问题时,我一开始也发现了同样的问题。我建议删除并重新添加新的.xcdatamodeld文件到您的项目中,然后重新构建。希望会有帮助!

#5


0  

Swift 3 Solution

斯威夫特3解决方案

1. Set the Persistent Store options for automatic migration in the app delegate.

1。设置应用程序委托中自动迁移的持久存储选项。

Change your persistentStoreCoordinator creation to this (replace SingleViewCoreData.sqlite):

将您的persistentStoreCoordinator创建更改为这个(替换SingleViewCoreData.sqlite):

lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {


let coordinator: NSPersistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.appendingPathComponent("SingleViewCoreData.sqlite")

let options = [
  NSMigratePersistentStoresAutomaticallyOption : Int(true),
  NSInferMappingModelAutomaticallyOption : Int(true)
]

do {

  try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: options)

} catch {

  print(error)
}

return coordinator

}()

2. Version your Data Model and Edit the new file.

2。修改数据模型并编辑新文件。

Select your xcdatamodel file Editor>Add Model Version - add a name for your new model

选择您的xcdatamodel文件编辑器>添加模型版本——为您的新模型添加一个名称