背景
以前版本的應用程序集屬性爲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的。
在上CoreData手動遷移MyAppAppDelegate persistentStoreCoordinator轉
// 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
在窗口,顯示右側窗格中的實用程序。
在窗口中,選擇實體映射EnvironmentToEnvironment
在右側的Entity Mapping中,選擇Custom Policy,然後輸入MyAppToMyAppVersion2MigrationPolicy。
保存文件。
參考文獻:
Zarra,核心數據第5章第87頁http://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,iOS的專業核心數據Ch 8 p273
不幸的是,這是行不通的。自動遷移不會修復現有的負整數值。 –
會發生什麼?從Int16到Int32仍然允許負數。你能舉一個例子嗎? –
自動遷移確實修復了新的數據庫字段。但是,已存儲的值也需要進行遷移。快速解決方法是在從db讀取它們之後修復這些值:NSInteger myInt32 = databaseInt16 + 65536; –