Objects not loading on second request in Restkit - iphone

I'm sending off 2 requests simultaneously with Restkit and I receive a response back from both of them, but only one of the requests receives any objects. If I send them off one by one, then my objectloader receives all objects.
First request:
self.firstObjectManager = [RKObjectManager sharedManager];
[self.firstObjectManager loadObjectsAtResourcePath:[NSString stringWithFormat: #"/%#.json", subUrl] usingBlock:^(RKObjectLoader *loader){
[loader.mappingProvider setObjectMapping:designArrayMapping forKeyPath:#""];
loader.userData = #"design";
loader.delegate = self;
[loader sendAsynchronously];
}];
Second request:
self.secondObjectManager = [RKObjectManager sharedManager];
[self.secondObjectManager loadObjectsAtResourcePath:[NSString stringWithFormat: #"/%#.json", subUrl] usingBlock:^(RKObjectLoader *loader){
[loader.mappingProvider setObjectMapping:designerMapping forKeyPath:#""];
loader.userData = #"designer";
loader.delegate = self;
[loader sendAsynchronously];
}];
My objecloader:
-(void)objectLoader:(RKObjectLoader *)objectLoader didLoadObjects:(NSArray *)objects
{
//NSLog(#"This happened: %#", objectLoader.userData);
if (objectLoader.userData == #"design") {
NSLog(#"Design happened: %i", objects.count);
}else if(objectLoader.userData == #"designer"){
NSLog(#"designer: %#", [objects objectAtIndex:0]);
}
}
My response:
2012-11-18 14:36:19.607 RestKitTest5[14220:c07] Started loading of request: designer
2012-11-18 14:36:22.575 RestKitTest5[14220:c07] I restkit.network:RKRequest.m:680:-[RKRequest updateInternalCacheDate] Updating cache date for request <RKObjectLoader: 0x95c3160> to 2012-11-18 19:36:22 +0000
2012-11-18 14:36:22.576 RestKitTest5[14220:c07] response code: 200
2012-11-18 14:36:22.584 RestKitTest5[14220:c07] Design happened: 0
2012-11-18 14:36:22.603 RestKitTest5[14220:c07] I restkit.network:RKRequest.m:680:-[RKRequest updateInternalCacheDate] Updating cache date for request <RKObjectLoader: 0xa589b50> to 2012-11-18 19:36:22 +0000
2012-11-18 14:36:22.605 RestKitTest5[14220:c07] response code: 200
2012-11-18 14:36:22.606 RestKitTest5[14220:c07] designer: <DesignerData: 0xa269fc0>
Update: Setting my base url
RKURL *baseURL = [RKURL URLWithBaseURLString:#"http://iphone.meer.li"];
[RKObjectManager setSharedManager:[RKObjectManager managerWithBaseURL:baseURL]];
Solution
Problem was that I used the shared manager for both object managers, so I ended up doing:
RKURL *baseURL = [RKURL URLWithBaseURLString:#"http://iphone.meer.li"];
RKObjectManager *myObjectManager = [[RKObjectManager alloc] initWithBaseURL:baseURL];
self.firstObjectManager = myObjectManager;
and:
RKURL *baseURL = [RKURL URLWithBaseURLString:#"http://iphone.meer.li"];
RKObjectManager *myObjectManager = [[RKObjectManager alloc] initWithBaseURL:baseURL];
self.secondObjectManager = myObjectManager;

Use block syntax for loading,
self.secondObjectManager = [RKObjectManager sharedManager];
[self.secondObjectManager loadObjectsAtResourcePath:[NSString stringWithFormat: #"/%#.json", subUrl] usingBlock:^(RKObjectLoader *loader){
[loader.mappingProvider setObjectMapping:designerMapping forKeyPath:#""];
loader.userData = #"designer";
loader.onDidLoadObjects = ^(NSArray *objects){
NSLog(#"Loaded objects %#", objects);
};
loader.onDidFailedWithError = ^(NSError *error){
NSLog(#"Failed with error %#", error.userInfo);
}
}];
Edit
Use your own object manager and retain it and then use it this way,
Do not use sharedManager instead alloc/init it and provide it objectstore and see. Hope this helps you,
[self.objectManager loadObjectsAtResourcePath:resourcePath usingBlock:^(RKObjectLoader *loader){
[loader.mappingProvider setMapping:[MyClass mapping] forKeyPath:#""];
loader.onDidLoadObjects = ^(NSArray *objects){
};
loader.onDidLoadResponse = ^(RKResponse *response){
NSLog(#"Loaded response %#", response.bodyAsString);
};
loader.onDidFailLoadWithError = ^(NSError *error){
NSLog(#"Error occurred ... %#", error.userInfo);
};
}];

Related

RestKit loadObjects

iam using restKit, to send and receive data from server... iam getting back
{
"request":"globalUpdate",
"updateRevision":2,
"updatedObjects":{
"users":[
{
id:"someid1",
name:"somename"
},
{
id:"someid2",
name:"somename2",
}
]
}
}
i want to use
[[RKObjectManager sharedManager] loadObjectsAtResourcePath:nil usingBlock:^(RKObjectLoader * loader){)];
to load only objects inside updatedObjects into CoreData and request, updateRevision into NSDictionary
so in
loader.onDidLoadObjects = ^(NSArray *objects) {
}
the first object is the Dictionary and the later one are CoreData
Well this is the matter of your choice which object you use for the coredata and which for your own purpose. RKObjectLoader also provides onDidLoadResponse block which has a reference to the response which you could use for your own use.
[myobjectManager loadObjectsAtResourcePath:resourcePath usingBlock:^(RKObjectLoader *loader) {
loader.mappingProvider = [RKObjectMappingProvider mappingProviderUsingBlock:^(RKObjectMappingProvider *provider) {
[provider setObjectMapping:[MyClass mapping] forKeyPath:#"updatedObjects"];
loader.onDidLoadObjects = ^(NSArray *objects){
};
loader.onDidLoadResponse = ^(RKResponse *response){
// NSData * data = [response data];
id object = [response parsedBody:nil];
// now parse the data yourself which will give you
// the entire json in NSData for and parse it,
// extract the component you need
};
loader.onDidFailWithError = ^(NSError *error){
};
}];
}];

Restkit MultiForm Post with an Image

Problem
I've been trying to post to the server with a multiform request that includes an image attachment. I haven't had trouble getting the image to the server, it is the other information that is not sending correctly.
Details
I'm using object mapping to configure several different attributes when receiving objects from the server:
//Using a custom class to map object I receive to
RKObjectMapping * memoryMapper = [RKObjectMapping mappingForClass:[MemoContent class]];
[memoryMapper mapAttributes:#"created", #"user", #"participants", #"tags", #"text", #"kind", #"video", #"location", nil];
[memoryMapper mapKeyPath:#"_id" toAttribute:#"memoryID"];
//MediaMapper handles the data needed for the Image attachments
RKObjectMapping * mediaMapper = [RKObjectMapping mappingForClass:[MemoMedia class]];
[mediaMapper mapKeyPath:#"processed" toAttribute:#"processed"];
[mediaMapper mapKeyPath:#"original" toAttribute:#"original"];
[mediaMapper mapKeyPath:#"mime" toAttribute:#"mimeType"];
[memoryMapper mapKeyPath:#"media" toRelationship:#"rawMedia" withMapping:mediaMapper];
//
[[RKObjectManager sharedManager].mappingProvider setMapping:memoryMapper forKeyPath:#"memories"];
[RKObjectManager sharedManager].serializationMIMEType = RKMIMETypeFormURLEncoded;
[RKObjectManager sharedManager].acceptMIMEType = RKMIMETypeJSON;
Then, when it comes time to post a photo I update configurations as follows:
RKObjectMapping * memoryMapper = [RKObjectMapping mappingForClass:[MemoContent class]];
[memoryMapper mapAttributes:#"created", #"participants", nil];
[[RKObjectManager sharedManager].mappingProvider setSerializationMapping:memoryMapper forClass:[MemoContent class]];
[[RKObjectManager sharedManager].mappingProvider setMapping:memoryMapper forKeyPath:#"memory"];
Participants are people tagged with the photo. Here is how I'm posting it, similar to this https://github.com/RestKit/RestKit/wiki/Attach-a-File-to-an-RKObjectLoader
[[RKObjectManager sharedManager] postObject:theMemory usingBlock:^(RKObjectLoader * loader){
RKObjectMapping* serializationMapping = [[[RKObjectManager sharedManager] mappingProvider] serializationMappingForClass:[MemoContent class]];
NSLog(#"serializationMapping: %#", serializationMapping);
loader.delegate = APP; //main app delegate posting, updating
NSError* error = nil;
RKObjectSerializer * serializer = [[RKObjectSerializer alloc] initWithObject:theMemory mapping:serializationMapping];
NSDictionary * dictionary = [serializer serializedObject:&error];
RKParams * params = [RKParams paramsWithDictionary:dictionary];
NSData * imageData = UIImagePNGRepresentation(theMemory.photo); //image data
[params setData:imageData MIMEType:#"image/png" forParam:#"attachment"];
loader.params = params;
loader.serializationMIMEType = RKMIMETypeFormURLEncoded;
}];
The server is receiving the image as planned, and actually does receive the 'created' and 'participants' unfortunately it's in a strange format that the server doesn't understand. It includes line breaks and such participants (\n 19843589323 \n created: \n 3-31-2012 00:00 (something like that, I will update when I have access to the logs.
I will give you any extra info you need. Would offer reputation for it if I had enough to do so ;)
In RestKit 0.20.0-pre3, RKObjectManager does have method multipartFormRequestWithObject:method:path:parameters:constructingBodyWithBlock:
An example of this task can be found at the RestKit Github page:
Article *article = [Article new];
UIImage *image = [UIImage imageNamed:#"some_image.png"];
// Serialize the Article attributes then attach a file
NSMutableURLRequest *request = [[RKObjectManager sharedManager] multipartFormRequestWithObject:article method:RKRequestMethodPOST path:nil parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:UIImagePNGRepresentation(image)
name:#"article[image]"
fileName:#"photo.png"
mimeType:#"image/png"];
}];
RKObjectRequestOperation *operation = [[RKObjectManager sharedManager] objectRequestOperationWithRequest:request success:nil failure:nil];
[[RKObjectManager sharedManager] enqueueObjectRequestOperation:operation]; // NOTE: Must be enqueued rather than started

Restkit Get with Params & Block with Shared Client

It won't let me attached the params to the request, what am I doing wrong? Params is a Dictionary and endString adds to the sharedClient baseURL.
[[RKClient sharedClient] get:endString usingBlock:^(RKRequest *loader){
loader.params = [RKParams paramsWithDictionary:params];
loader.onDidLoadResponse = ^(RKResponse *response) {
[self parseJSONDictFromResponse:response];
};
loader.onDidFailLoadWithError = ^(NSError *error) {
NSLog(#"error2:%#",error);
};
}];
I get this error:RestKit was asked to retransmit a new body stream for a request. Possible connection error or authentication challenge?
I think you are on the right track. Below is from a working example I found here, about 2/3 the way down the page. Another option for you may be to append the params directly to the URL. I'm not sure if that's feasible for you, but if your parameters are simple then it may be.
- (void)authenticateWithLogin:(NSString *)login password:(NSString *)password onLoad:(RKRequestDidLoadResponseBlock)loadBlock onFail:(RKRequestDidFailLoadWithErrorBlock)failBlock
{
[[RKClient sharedClient] post:#"/login" usingBlock:^(RKRequest *request) {
request.params = [NSDictionary dictionaryWithKeysAndObjects:
#"employee[email]", login,
#"employee[password]", password,
nil];
request.onDidLoadResponse = ^(RKResponse *response) {
id parsedResponse = [response parsedBody:NULL];
NSString *token = [parsedResponse valueForKey:#"authentication_token"];
//NSLog(#"response: [%#] %#", [parsedResponse class], parsedResponse);
if (token.length > 0) {
NSLog(#"response status: %d, token: %#", response.statusCode, token);
[[RKClient sharedClient] setValue:token forHTTPHeaderField:#"X-Rabatme-Auth-Token"];
if (loadBlock) loadBlock(response);
}
[self fireErrorBlock:failBlock onErrorInResponse:response];
};
request.onDidFailLoadWithError = failBlock;
}];
}
You should also take a look at this SO question: RestKit GET query parameters.

Include image using NSMutabaleDictionary with RKClient and receiving on the Php Server

1 - How can I include a picture using NSMutableDictionary with RestKit Client?
My server receives data from NSMutableDictionary in my code below.
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
[dictionary setObject:usernameTextfield.text forKey:#"username"];
[client put:#"/main/insert" params:params delegate:self];
but how can I attach an image at the same time?
On the other hand, RKParams doesn't work for me on my server side.
RKParams *params=[[RKParams alloc]init];
imageData = UIImagePNGRepresentation(imageField.image);
[params setData:imageData MIMEType:#"image/png" forParam:#"image"];
Rest server code:
public function insert_put()
{
$username = $this->put('username');
$this->model->insertPost($username);
//Question number 2.
$data['success'] = 'added successfully';
$this->response($data, 200);
}
2 - How can I receive it from my server(php) ? I'm using put option to this.
I just do the following
- (void) upload: (UIImage *) pic onLoad:(RKObjectLoaderDidLoadObjectBlock) loadBlock onError:(RKRequestDidFailLoadWithErrorBlock)failBlock{
RKParams* imageParams = [RKParams params];
NSData* imageData = UIImageJPEGRepresentation(pic, 0.7f);
[imageParams setData:imageData MIMEType:#"image/jpg" forParam:#"FileUpload"];
NSString *resourcePath = #"/api/upload/";
RKObjectMapping *mapping = [[RKObjectManager sharedManager].mappingProvider objectMappingForClass:[KFMedia class]];
[[RKObjectManager sharedManager] loadObjectsAtResourcePath:resourcePath usingBlock:^(RKObjectLoader *loader) {
loader.method = RKRequestMethodPOST;
loader.params = imageParams;
[self settingsForLoader:loader withMapping:mapping onLoad:loadBlock onError:failBlock];
}];
}
- (void) settingsForLoader: (RKObjectLoader *) loader withMapping: (RKObjectMapping *) mapping onLoad:(RKObjectLoaderDidLoadObjectBlock) loadBlock onError:(RKRequestDidFailLoadWithErrorBlock)failBlock{
loader.objectMapping = mapping;
loader.delegate = self;
loader.onDidLoadObject = loadBlock;
loader.onDidFailWithError = ^(NSError * error){
//NSLog(#"%#",error);
};
loader.onDidFailLoadWithError = failBlock;
loader.onDidLoadResponse = ^(RKResponse *response) {
[self fireErrorBlock:failBlock onErrorInResponse:response];
};
}
Your RestKit code looks fine, I think it is your php code that is failing. RestKit will upload the image as part of a multipart/form-data. This info will not appear in your normal _PUT array like your username did. I'm not sure what frameworks you are using (Is that the REST Controller library?), but you can access the file using _FILES['image'] or whatever your server framework uses. $this->files('image') maybe?
EDIT:
To create a mixed param file try this:
NSDictionary* strings = [NSDictionary dictionaryWithObjectsAndKeys: usernameTextfield.text, #"username", nil];
NSData* image = UIImagePNGRepresentation(imageView.image);
RKParams* params = [[RKParams alloc] initWithDictionary: strings];
[params setData: image MIMEType: #"image/png" withParameter: #"image"];
//And send it
[client put:#"/main/insert" params:params delegate:self];
But now you can not use $this->put, but instead $this->upload. For example:
$data = $this->upload->data();
$username = $data['username'];
$imagefile = $data['image'];

CoreData versioning and blocking lightweight migration

I have enabled versioning of my Core Data model and have been using light weight migration. My code always tries to do lightweight migration and then if that fails because the model are incompatible it falls back to deleting all existing data and refetching from the server.
So lightweight migration is just used for efficiency and isn't required for correctness.
What I want to do now is make a change to my model which in theory lightweight migration could handle but in fact I need new data from the server. I want to somehow flag the model and not upgradeable via lightweight migration. For example if a field name has not changed but the meaning of that field has changed in such a way that the old code is incompatible with the new code base. (This is just an example.)
Has anyone found a way to flag a two models as incompatible so lightweight migration won't upgrade them?
I've struggled with the same problem before.
I have a method that will attempt to migrate data using Mapping Models which is what you should use if you're going to turn off lightweight migration.
If you aren't going to do a lot of fancy data mapping, xcode will automatically create a mapping model that will work exactly like lightweight migration. All you have to do is create a new "Mapping Model" file each time you add a new version to Core Data. Just go to "File -> New -> New File" and under Core Data there should be a Mapping Model template. Select it and choose the source and destination versions.
I don't have my code openly available on github so I'll just post the migration method here.
- (BOOL)progressivelyMigrateURL:(NSURL*)sourceStoreURL ofType:(NSString*)type toModel:(NSManagedObjectModel*)finalModel
{
NSError *error = nil;
// if store dosen't exist skip migration
NSString *documentDir = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents"];
if(![NSBundle pathForResource:#"YongoPal" ofType:#"sqlite" inDirectory:documentDir])
{
migrationProgress = 1.0;
[self performSelectorOnMainThread:#selector(updateMigrationProgress) withObject:nil waitUntilDone:YES];
// remove migration view
[self.migrationView performSelectorOnMainThread:#selector(setHidden:) withObject:[NSNumber numberWithBool:YES] waitUntilDone:YES];
[self.migrationView performSelectorOnMainThread:#selector(removeFromSuperview) withObject:nil waitUntilDone:YES];
self.migrationView = nil;
self.migrationProgressLabel = nil;
self.migrationProgressView = nil;
self.migrationSpinner = nil;
return YES;
}
//START:progressivelyMigrateURLHappyCheck
NSDictionary *sourceMetadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:type URL:sourceStoreURL error:&error];
if (!sourceMetadata)
{
return NO;
}
if ([finalModel isConfiguration:nil compatibleWithStoreMetadata:sourceMetadata])
{
migrationProgress = 1.0;
[self performSelectorOnMainThread:#selector(updateMigrationProgress) withObject:nil waitUntilDone:YES];
// remove migration view
[self.migrationView performSelectorOnMainThread:#selector(setHidden:) withObject:[NSNumber numberWithBool:YES] waitUntilDone:YES];
[self.migrationView performSelectorOnMainThread:#selector(removeFromSuperview) withObject:nil waitUntilDone:YES];
self.migrationView = nil;
self.migrationProgressLabel = nil;
self.migrationProgressView = nil;
self.migrationSpinner = nil;
error = nil;
return YES;
}
else
{
migrationProgress = 0.0;
[self.migrationView performSelectorOnMainThread:#selector(setHidden:) withObject:NO waitUntilDone:YES];
[self performSelectorOnMainThread:#selector(updateMigrationProgress) withObject:nil waitUntilDone:YES];
}
//END:progressivelyMigrateURLHappyCheck
//START:progressivelyMigrateURLFindModels
//Find the source model
NSManagedObjectModel *sourceModel = [NSManagedObjectModel mergedModelFromBundles:nil forStoreMetadata:sourceMetadata];
if(sourceModel == nil)
{
NSLog(#"%#", [NSString stringWithFormat:#"Failed to find source model\n%#", [sourceMetadata description]]);
return NO;
}
//Find all of the mom and momd files in the Resources directory
NSMutableArray *modelPaths = [NSMutableArray array];
NSArray *momdArray = [[NSBundle mainBundle] pathsForResourcesOfType:#"momd" inDirectory:nil];
for (NSString *momdPath in momdArray)
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSString *resourceSubpath = [momdPath lastPathComponent];
NSArray *array = [[NSBundle mainBundle] pathsForResourcesOfType:#"mom" inDirectory:resourceSubpath];
[modelPaths addObjectsFromArray:array];
[pool drain];
}
NSArray* otherModels = [[NSBundle mainBundle] pathsForResourcesOfType:#"mom" inDirectory:nil];
[modelPaths addObjectsFromArray:otherModels];
if (!modelPaths || ![modelPaths count])
{
//Throw an error if there are no models
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setValue:#"No models found in bundle" forKey:NSLocalizedDescriptionKey];
//Populate the error
error = [NSError errorWithDomain:#"com.yongopal.coredata" code:500 userInfo:dict];
if([[self.prefs valueForKey:#"debugMode"] isEqualToString:#"Y"])
{
NSLog(#"error: %#", error);
}
return NO;
}
//END:progressivelyMigrateURLFindModels
//See if we can find a matching destination model
//START:progressivelyMigrateURLFindMap
NSMappingModel *mappingModel = nil;
NSManagedObjectModel *targetModel = nil;
NSString *modelPath = nil;
for(modelPath in modelPaths)
{
targetModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:[NSURL fileURLWithPath:modelPath]];
mappingModel = [NSMappingModel mappingModelFromBundles:nil forSourceModel:sourceModel destinationModel:targetModel];
//If we found a mapping model then proceed
if(mappingModel)
{
break;
}
else
{
//Release the target model and keep looking
[targetModel release];
targetModel = nil;
}
}
//We have tested every model, if nil here we failed
if (!mappingModel)
{
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setValue:#"No mapping models found in bundle" forKey:NSLocalizedDescriptionKey];
error = [NSError errorWithDomain:#"com.yongopal.coredata" code:500 userInfo:dict];
if([[self.prefs valueForKey:#"debugMode"] isEqualToString:#"Y"])
{
NSLog(#"error: %#", error);
}
return NO;
}
//END:progressivelyMigrateURLFindMap
//We have a mapping model and a destination model. Time to migrate
//START:progressivelyMigrateURLMigrate
NSMigrationManager *manager = [[NSMigrationManager alloc] initWithSourceModel:sourceModel destinationModel:targetModel];
// reg KVO for migration progress
[manager addObserver:self forKeyPath:#"migrationProgress" options:NSKeyValueObservingOptionNew context:NULL];
NSString *modelName = [[modelPath lastPathComponent] stringByDeletingPathExtension];
NSString *storeExtension = [[sourceStoreURL path] pathExtension];
NSString *storePath = [[sourceStoreURL path] stringByDeletingPathExtension];
//Build a path to write the new store
storePath = [NSString stringWithFormat:#"%#.%#.%#", storePath, modelName, storeExtension];
NSURL *destinationStoreURL = [NSURL fileURLWithPath:storePath];
if (![manager migrateStoreFromURL:sourceStoreURL type:type options:nil withMappingModel:mappingModel toDestinationURL:destinationStoreURL destinationType:type destinationOptions:nil error:&error])
{
if([[self.prefs valueForKey:#"debugMode"] isEqualToString:#"Y"])
{
NSLog(#"error: %#", error);
}
[targetModel release];
[manager removeObserver:self forKeyPath:#"migrationProgress"];
[manager release];
return NO;
}
[targetModel release];
[manager removeObserver:self forKeyPath:#"migrationProgress"];
[manager release];
//END:progressivelyMigrateURLMigrate
//Migration was successful, move the files around to preserve the source
//START:progressivelyMigrateURLMoveAndRecurse
NSString *guid = [[NSProcessInfo processInfo] globallyUniqueString];
guid = [guid stringByAppendingPathExtension:modelName];
guid = [guid stringByAppendingPathExtension:storeExtension];
NSString *appSupportPath = [storePath stringByDeletingLastPathComponent];
NSString *backupPath = [appSupportPath stringByAppendingPathComponent:guid];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager moveItemAtPath:[sourceStoreURL path] toPath:backupPath error:&error])
{
if([[self.prefs valueForKey:#"debugMode"] isEqualToString:#"Y"])
{
NSLog(#"error: %#", error);
}
//Failed to copy the file
return NO;
}
//Move the destination to the source path
if (![fileManager moveItemAtPath:storePath toPath:[sourceStoreURL path] error:&error])
{
if([[self.prefs valueForKey:#"debugMode"] isEqualToString:#"Y"])
{
NSLog(#"error: %#", error);
}
//Try to back out the source move first, no point in checking it for errors
[fileManager moveItemAtPath:backupPath toPath:[sourceStoreURL path] error:nil];
return NO;
}
//We may not be at the "current" model yet, so recurse
return [self progressivelyMigrateURL:sourceStoreURL ofType:type toModel:finalModel];
//END:progressivelyMigrateURLMoveAndRecurse
}
This is an edited version of a method I got from some Core Data book I can't remember the title of. I wish I could give credit to the author. :S
Beware, I have some code in here that you should remove in your implementation. It's mostly stuff I use to update the view on the progress of the migration.
You can use this method like so:
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"YongoPal.sqlite"];
// perform core data migrations if necessary
if(![self progressivelyMigrateURL:storeURL ofType:NSSQLiteStoreType toModel:self.managedObjectModel])
{
// reset the persistent store on fail
NSString *documentDir = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents"];
NSError *error = nil;
[[NSFileManager defaultManager] removeItemAtPath:[NSBundle pathForResource:#"YongoPal" ofType:#"sqlite" inDirectory:documentDir] error:&error];
}
else
{
NSLog(#"migration succeeded!");
}
Remember to remove the lightweight migration option before you use this.
Apple's Core Data Model Versioning and Data Migration Programming Guide addresses what to do if "you have two versions of a model that Core Data would normally treat as equivalent that you want to be recognized as being different", which I think is what you're asking.
The answer is to set the versionHashModifier on one of your Entities or Properties in the new model.
In your example, you'd do that on the field whose meaning has changed.