xcode 核心数据更改属性从整数 16 到整数 32

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7765300/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 22:07:20  来源:igfitidea点击:

Core Data change property from Integer 16 to Integer 32

xcodecore-datacore-data-migration

提问by Chris Rutkowski

I'm having a very serious problem. The application is live, but unfortunately it's fails on iOS 5, and I need to post an update.

我有一个非常严重的问题。该应用程序已上线,但不幸的是它在 iOS 5 上失败了,我需要发布更新。

The thing is the ID column of few entities is in Integer 16, but I need to be changed to Integer 32.

问题是少数实体的ID列在整数16中,但我需要更改为整数32。

It was clearly my mistake, the model was created very long time ago, and it was only being reused. To my surprise (now) on iOS 4, Integer 16 in Core Data could easily keep number as big as 500 000 (bug?), but it doesn't work like that now - it gives me invalid numbers.

这显然是我的错误,模型是很久以前创建的,只是被重用了。令我惊讶的是(现在)在 iOS 4 上,Core Data 中的 Integer 16 可以轻松地将数字保持在 500 000(错误?)

Application is live, has it success and Core Data is also used to keep the users scores, achievements and so on, what I don't want to remove, forcing them to reinstall the application. What is the best approach to simply change about ten of properties in different entities from Integer 16 to Integer 32?

应用程序已上线,是否成功,Core Data 还用于保存用户的分数、成就等,我不想删除这些内容,迫使他们重新安装应用程序。简单地将不同实体中的大约十个属性从整数 16 更改为整数 32 的最佳方法是什么?

Of course I know the names and entities for those properties.

当然,我知道这些属性的名称和实体。

If I just change the Type column for those properties in the xcdatamodeld file it will work, for new user, but what about existing users, that already have sqlite file in their Documents folder. I believe I need to change the persistent store coordinator somehow.

如果我只是在 xcdatamodeld 文件中更改这些属性的 Type 列,它将对新用户起作用,但是对于现有用户呢,他们的 Documents 文件夹中已经有 sqlite 文件。我相信我需要以某种方式更改持久存储协调器。

And also what do you thing about the performance, there are about 10 properties that news to be changed from 16 to 32, but Core Data have in usual cases more than 100 000 objects inside.

还有你对性能有什么看法,大约有 10 个属性要从 16 更改为 32,但通常情况下,Core Data 内部有超过 100 000 个对象。

Regards

问候

回答by beepscore

Background
Previous version of app set attribute as 16 bit in Core Data. This was too small to hold large values greater than approx 32768.
int 16 uses 1 bit to represent sign, so maximum value = 2^15 = 32768
In iOS 5, these values overflowed into negative numbers.

背景
以前版本的应用程序在 Core Data 中将属性设置为 16 位。这太小了,无法容纳大于大约 32768 的大值。
int 16 使用 1 位来表示符号,因此最大值 = 2^15 = 32768
在 iOS 5 中,这些值溢出为负数。

34318 became -31218
36745 became -28791

34318 变成了 -31218
36745 变成了 -28791

To repair these negative values, add 2^16 = 65536
Note this solution works only if the original value was less than 65536.

要修复这些负值,请添加 2^16 = 65536
注意此解决方案仅在原始值小于 65536 时才有效。

Add a new model
In file navigator, select MyApp.xcdatamodeld
Choose menu Editor/Add Model Version
Version name: proposes "MyApp 2" but you can change e.g. to MyAppVersion2
Based on model: MyApp

添加新模型
在文件导航器中,选择 MyApp.xcdatamodeld
选择菜单编辑器/添加模型版本
版本名称:建议“MyApp 2”但您可以更改为例如 MyAppVersion2
基于模型:MyApp

In new MyAppVersion2.xcdatamodel change attribute type from integer 16 to integer 64.

在新的 MyAppVersion2.xcdatamodel 中,将属性类型从整数 16 更改为整数 64。

In file navigator, select directory MyApp.xcdatamodeld

在文件导航器中,选择目录 MyApp.xcdatamodeld

Open right pane inspector, Versioned Core Data Model Current change from MyApp to MyAppVersion2. In left pane file navigator, green check mark moves from MyApp.xcdatamodel to MyAppVersion2.xcdatamodel.

打开右窗格检查器,版本化核心数据模型当前从 MyApp 更改为 MyAppVersion2。在左窗格文件导航器中,绿色复选标记从 MyApp.xcdatamodel 移动到 MyAppVersion2.xcdatamodel。

In MyAppAppDelegate managedObjectModel do not change resource name from @"MyApp"

在 MyAppAppDelegate managedObjectModel 中不要从@"MyApp"更改资源名称

In Xcode select folder ModelClasses.
File/Add Core Data Mapping Model.

在 Xcode 中选择文件夹 ModelClasses。
文件/添加核心数据映射模型。

Choose source data model MyApp.xcdatamodel
Choose target data model MyAppVersion2.xcdatamodel
Save As MyAppToMyAppVersion2.xcmappingmodel

选择源数据模型 MyApp.xcdatamodel
选择目标数据模型 MyAppVersion2.xcdatamodel
另存为 MyAppToMyAppVersion2.xcmappingmodel

Add to target MyApp.

添加到目标 MyApp。

In MyAppAppDelegate persistentStoreCoordinator turn on CoreData manual migration

在 MyAppAppDelegate persistentStoreCoordinator 中开启 CoreData 手动迁移

// Returns the persistent store coordinator for the application.
// If the coordinator doesn't already exist, it is created
// and the application's store added to it.
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

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

    NSURL *storeURL = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] 
                                               stringByAppendingPathComponent: @"MyApp.sqlite"]];

    NSError *error = nil;
    persistentStoreCoordinator_ = [[NSPersistentStoreCoordinator alloc] 
                                   initWithManagedObjectModel:[self managedObjectModel]];

    // Set Core Data migration options
    // For automatic lightweight migration set NSInferMappingModelAutomaticallyOption to YES
    // For manual migration using a mapping model set NSInferMappingModelAutomaticallyOption to NO
    NSDictionary *optionsDictionary = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], 
                                       NSMigratePersistentStoresAutomaticallyOption, 
                                       [NSNumber numberWithBool:NO], 
                                       NSInferMappingModelAutomaticallyOption, 
                                       nil];

    if (![persistentStoreCoordinator_ addPersistentStoreWithType:NSSQLiteStoreType 
                                                   configuration:nil 
                                                             URL:storeURL 
                                                         options:optionsDictionary 
                                                           error:&error])
    {
        // handle the error
        NSString *message = [[NSString alloc]
                             initWithFormat:@"%@, %@", error, [error userInfo]];

        UIAlertViewAutoDismiss *alertView = [[UIAlertViewAutoDismiss alloc]     
                                             initWithTitle:NSLocalizedString(@"Sorry, Persistent Store Error.  Please Quit.", @"")
                                             message:message
                                             delegate: nil
                                             cancelButtonTitle:NSLocalizedString(@"OK", @"") 
                                             otherButtonTitles:nil]; 
        [message release];
        [alertView show];
        [alertView release];
    }    

    return persistentStoreCoordinator_;
}

Add a migration policy
MyAppToMyAppVersion2MigrationPolicy
The following example converts one entity "Environment" with an integer attribute "FeedID" and a string attribute "title".

添加迁移策略
MyAppToMyAppVersion2MigrationPolicy
下面的示例转换一个实体“Environment”,它具有整数属性“FeedID”和字符串属性“title”。

- (BOOL)createDestinationInstancesForSourceInstance:(NSManagedObject *)aSource
                                  entityMapping:(NSEntityMapping *)mapping
                                        manager:(NSMigrationManager *)migrationManager
                                          error:(NSError **)error {
    NSEntityDescription *aSourceEntityDescription = [aSource entity];
    NSString *aSourceName = [aSourceEntityDescription valueForKey:@"name"];

    NSManagedObjectContext *destinationMOC = [migrationManager destinationContext];
    NSManagedObject *destEnvironment;
    NSString *destEntityName = [mapping destinationEntityName];

    if ([aSourceName isEqualToString:kEnvironment])
    {
        destEnvironment = [NSEntityDescription
                           insertNewObjectForEntityForName:destEntityName
                           inManagedObjectContext:destinationMOC];

        // attribute feedID
        NSNumber *sourceFeedID = [aSource valueForKey:kFeedID];
        if (!sourceFeedID)
        {
            // Defensive programming.
            // In the source model version, feedID was required to have a value
            // so excecution should never get here.
            [destEnvironment setValue:[NSNumber numberWithInteger:0] forKey:kFeedID];
        } 
        else
        {
            NSInteger sourceFeedIDInteger = [sourceFeedID intValue];        
            if (sourceFeedIDInteger < 0)
            {            
                // To correct previous negative feedIDs, add 2^16 = 65536            
                NSInteger kInt16RolloverOffset = 65536;            
                NSInteger destFeedIDInteger = (sourceFeedIDInteger + kInt16RolloverOffset);
                NSNumber *destFeedID = [NSNumber numberWithInteger:destFeedIDInteger]; 
                [destEnvironment setValue:destFeedID forKey:kFeedID];

            } else
            {
                // attribute feedID previous value is not negative so use it as is
                [destEnvironment setValue:sourceFeedID forKey:kFeedID];
            }
        }

        // attribute title (don't change this attribute)
        NSString *sourceTitle = [aSource valueForKey:kTitle];
        if (!sourceTitle)
        {
            // no previous value, set blank
            [destEnvironment setValue:@"" forKey:kTitle];
        } else
        {
            [destEnvironment setValue:sourceTitle forKey:kTitle];
        }

        [migrationManager associateSourceInstance:aSource
                          withDestinationInstance:destEnvironment
                                 forEntityMapping:mapping];

        return YES;
    } else
    {
        // don't remap any other entities
        return NO;
    }
}

In file navigator select MyAppToMyAppVersion2.xcmappingmodel
In window, show right side utilities pane.
In window, select Entity Mappings EnvironmentToEnvironment
In right side Entity Mapping, choose Custom Policy enter MyAppToMyAppVersion2MigrationPolicy.
Save file.

在文件导航器中选择 MyAppToMyAppVersion2.xcmappingmodel
在窗口中,显示右侧实用程序窗格。
在窗口中,选择实体映射 EnvironmentToEnvironment
在右侧实体映射中,选择自定义策略输入 MyAppToMyAppVersion2MigrationPolicy。
保存存档。

References:

参考:

Zarra, Core Data Chapter 5 p 87 http://pragprog.com/book/mzcd/core-data

Zarra,核心数据第 5 章第 87 页 http://pragprog.com/book/mzcd/core-data

http://www.informit.com/articles/article.aspx?p=1178181&seqNum=7

http://www.informit.com/articles/article.aspx?p=1178181&seqNum=7

http://www.timisted.net/blog/archive/core-data-migration/

http://www.timisted.net/blog/archive/core-data-migration/

http://www.cocoabuilder.com/archive/cocoa/286529-core-data-versioning-non-trivial-value-expressions.html

http://www.cocoabuilder.com/archive/cocoa/286529-core-data-versioning-non-trivial-value-expressions.html

http://www.seattle-ipa.org/2011/09/11/coredata-and-integer-width-in-ios-5/

http://www.seattle-ipa.org/2011/09/11/coredata-and-integer-width-in-ios-5/

Privat, Pro Core Data for iOS Ch 8 p273

Privat, Pro Core Data for iOS Ch 8 p273

回答by Marcus S. Zarra

Turn on NSMigratePersistentStoresAutomaticallyOption' and 'NSInferMappingModelAutomaticallyOptionin your NSPersistentStoreand then create a second version of your model with the changes. Only do the integer changes to keep the migration simple. That will allow users who install your upgrade to migrate from the broken model to the corrected model.

打开NSMigratePersistentStoresAutomaticallyOption' and 'NSInferMappingModelAutomaticallyOption你的NSPersistentStore,然后创建与修改模型的第二个版本。只进行整数更改以保持迁移简单。这将允许安装升级的用户从损坏的模型迁移到更正的模型。

NOTE:This mustbe an automatic migration; a manual migration with a mapping model will not work.

注意:必须是自动迁移;使用映射模型的手动迁移将不起作用。

回答by kimmo

Just wants to confirm Marcus S. Zarra's answer with a small addition. It works good for us to some extent. We made the exact same error in our model. But it has a problem. Values over what seems to be 2^24 is converted to 16-bit values during the automatic migration, but saved as 32-bit but with wrong value.

只是想通过一点补充来确认 Marcus S. Zarra 的回答。它在某种程度上对我们有好处。我们在我们的模型中犯了完全相同的错误。但它有一个问题。超过 2^24 的值在自动迁移期间被转换为 16 位值,但保存为 32 位但值错误。

For example: 17 479 261 becomes 18 851

例如:17 479 261 变成 18 851

(17 479 261 mod (2^16)) - (2^16) = -18 851

(17 479 261 mod (2^16)) - (2^16) = -18 851

We downloaded the DB from the phone and looked in the database, and the number is changed in the DB.

我们从手机上下载了数据库,在数据库中查找,数据库中的数字发生了变化。

We have not yet solved this problem.

我们还没有解决这个问题。