Базовые данные изменяют свойство с целого числа 16 на целое число 32 - PullRequest
3 голосов
/ 14 октября 2011

У меня очень серьезная проблема.Приложение работает, но, к сожалению, оно не работает на iOS 5, и мне нужно опубликовать обновление.

Дело в том, что столбец идентификатора нескольких объектов находится в Integer 16, но мне нужно изменить его на Integer 32.

Это была явно моя ошибка, модель была создана очень давно, и она только использовалась повторно.К моему удивлению (сейчас) в iOS 4, целое число 16 в Core Data может легко сохранить число до 500 000 (ошибка?), Но теперь оно не работает так - оно дает мне недопустимые числа.

Приложение работает, имеет успех, и Core Data также используется для хранения результатов пользователей, достижений и т. Д., Которые я не хочу удалять, вынуждая их переустанавливать приложение.Как лучше всего просто поменять около десяти свойств в разных сущностях с Integer 16 на Integer 32?

Конечно, я знаю имена и сущности этих свойств.

Если я просто изменю столбец Тип для этих свойств в файле xcdatamodeld, он будет работать для нового пользователя, но как насчет существующих?пользователи, которые уже имеют файл sqlite в своей папке «Документы».Я считаю, что мне нужно как-то изменить координатор постоянного хранилища.

А также что вы думаете о производительности, есть около 10 свойств, которые новости должны быть изменены с 16 на 32, но Core Data имеют в обычных случаяхболее 100 000 предметов внутри.

С уважением

Ответы [ 3 ]

12 голосов
/ 16 ноября 2011

Фон
Предыдущая версия атрибута приложения установлена ​​как 16-битная в Базовых данных.Это было слишком мало, чтобы содержать большие значения, превышающие приблизительно 32768.
int 16 использует 1 бит для представления знака, поэтому максимальное значение = 2 ^ 15 = 32768
В iOS 5 эти значения переполнились отрицательными числами.

34318 стал -31218
36745 стал -28791

Чтобы исправить эти отрицательные значения, добавьте 2 ^ 16 = 65536
Обратите внимание, что это решение работает, только если исходное значение было меньше 65536.

Добавление новой модели
В файловом навигаторе выберите MyApp.xcdatamodeld
Выберите меню Редактор / Добавить версию модели
Имя версии: предлагается «MyApp 2», но выможно изменить, например, на MyAppVersion2
В зависимости от модели: MyApp

В новом MyAppVersion2.xcdatamodel изменить тип атрибута с целого числа 16 на целое число 64.

В файловом навигаторе выбрать каталог MyApp.xcdatamodeld

Инспектор открытой правой панели, Версионная модель данных ядра Текущее изменение с MyApp на MyAppVersion2.В навигаторе файлов левой панели зеленая галочка перемещается из MyApp.xcdatamodel в MyAppVersion2.xcdatamodel.

В MyAppAppDelegate managedObjectModel не меняйте имя ресурса из @ "MyApp"

В Xcode выберите папку ModelClasses.
Файл / Добавить базовую модель отображения данных.

Выбор исходной модели данных MyApp.xcdatamodel
Выбор целевой модели данных MyAppVersion2.xcdatamodel
Сохранить как MyAppToMyAppVersion2.xcmappingmodel

Добавить к цели MyApp.

В 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_;
}

Добавить политику миграции
MyAppToMyAppVersion2MigrationPolicy
В следующем примере выполняется преобразование одной сущности «Среда» с целочисленным атрибутом «FeedID» и строковым атрибутом «заголовок».

- (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;
    }
}

В файловом навигаторе выберите MyAppToMyAppVersion2.xcmappingmodel
В окне, показать правую панель утилит.
В окне выберите Entity Mappings Environ.mentToEnvironment
В правой части Entity Mapping выберите Custom Policy, введите MyAppToMyAppVersion2MigrationPolicy.
Сохранить файл.

Ссылки:

Zarra, Основные данные Глава 5 стр. 87http://pragprog.com/book/mzcd/core-data

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

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.seattle -ipa.org / 2011/09/ 11 / coredata-and-integer-width-in-ios-5 /

Privat, Pro Core Data для iOS Ch 8 p273

9 голосов
/ 14 октября 2011

Включите NSMigratePersistentStoresAutomaticallyOption' and 'NSInferMappingModelAutomaticallyOption в вашем NSPersistentStore, а затем создайте вторую версию вашей модели с изменениями.Делайте только целочисленные изменения, чтобы облегчить миграциюЭто позволит пользователям, установившим ваше обновление, перейти от поврежденной модели к исправленной модели.

ПРИМЕЧАНИЕ: Этот должен быть автоматической миграцией;ручная миграция с моделью сопоставления не будет работать.

0 голосов
/ 20 октября 2011

Просто хочу подтвердить ответ Маркуса С. Зарры небольшим дополнением.Это работает хорошо для нас в некоторой степени.Мы сделали точно такую ​​же ошибку в нашей модели.Но у него есть проблема.Значения, превышающие 2 ^ 24, преобразуются в 16-битные значения во время автоматической миграции, но сохраняются как 32-битные, но с неверным значением.

Например: 17 479 261 становится 18 851

(17 479 261 мод (2 ^ 16)) - (2 ^ 16) = -18 851

Мы скачали БД с телефона и посмотрели в базе, а номер изменился вБД.

Мы еще не решили эту проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...