As many of you, I have to delete my application in the simulator in order to reinstall a fresh version, where I update my database. Otherwise, it crashes with or without debug log (if it's Core Data, the debug log is pretty self explanatory).
My question is : since users won't probably delete their applications before updating through the app store, and since they'll most definitely want their "old" data after the upgrade,
Do we hav开发者_开发技巧e to develop a database migration script, or check in the applicationDidLaunch if the database changed, at every launch ?
Thanks !
I would definitely give you a 1-Star if my Data is lost after an update.
Core-Data versioning and migration is set up in a few minutes, at least the light-weight-part.
Have a look at this answer to as similar question
I have not personally used CoreData so have no idea if it has special tools for handling this. But, in general yes, you need to create and store SQL scripts that will migrate from each version of your app to the next.
When the app is installed, it should check the current version of the data model against the version of the data model used by the app. There should be a "delta" script to move from each version to each next version. Each of the deltas necessary to move from the current model to the necessary model should then be applied.
For example, if you have submitted 4 versions to the AppStore. You need a delta script to get from version 1 to 2, from 2 to 3 and from 3 to 4.
Each time the app launches it checks the current version of the data model against the executables desired version. If, for example, version 4 is installed on a device, but the user had never installed version 3, the app would launch. Check the current version of the model, which is 2. Compare it with the executable's version which is 4. And then apply the 2 to 3 script and then the 3 to 4 script.
The version number itself can be stored in the database and should be incremented after applying the deltas, either from the deltas themselves or automatically in the processing code.
The deltas can be stored either as constant strings in your code files or just as resource files in your project.
Edit: (here is my migration code)
+ (NSArray*) chop:(NSString*)sql {
NSMutableArray* list = [[NSMutableArray alloc] init];
NSMutableString* sb = [[NSMutableString alloc] init];
BOOL inside = FALSE;
for (int i=0;i<[sql length];i++) {
if ([sql characterAtIndex:i] == '\n') continue;
if ([sql characterAtIndex:i] == '\r') continue;
[sb appendFormat:@"%c",[sql characterAtIndex:i]];
if (!inside) {
if ([sql characterAtIndex:i] == '\'')
inside = TRUE;
else if ([sql characterAtIndex:i] == ';') {
[sb deleteCharactersInRange:NSMakeRange([sb length]-1,1)];
[list addObject:sb];
[sb release];
sb = [[NSMutableString alloc] init];
}
} else {
if ([sql characterAtIndex:i] == '\'')
inside = FALSE;
else if ([sql characterAtIndex:i] == '\\') {
i++;
[sb appendFormat:@"%c",[sql characterAtIndex:i]];
}
}
}
[sb release];
return [list autorelease];
}
+ (void) updateObjectModel {
[Log output:@"[migration]"];
int version;
@try {
int exist = [SQL queryLong:@"SELECT COUNT(*) FROM Variables WHERE Key='objectModelVersion'"];
if (exist)
version = [SQL retrieveInt:@"objectModelVersion"]+1;
else {
[Log output:@"[bootstrapping]"];
[SQL storeInt:@"objectModelVersion" as:1];
version = 2;
}
} @catch (NSException* e) {
[Log output:@"[initializing]"];
version = 0;
}
while (TRUE) {
NSString* filename = [NSString stringWithFormat:@"SQLite-%04d",version];
NSString* file = [[NSBundle mainBundle] pathForResource:filename ofType:@"sql"];
if (file) {
[Log output:[NSString stringWithFormat:@"[%d]",version]];
NSArray* commands = [SQL chop:[NSString stringWithContentsOfFile:file encoding:NSASCIIStringEncoding error:NULL]];
for (NSString* command in commands)
[SQL update:command];
[SQL storeInt:@"objectModelVersion" as:version];
} else break;
version++;
}
[Log output:@"[/migration]\n"];
}
精彩评论