2

I'm trying migrate NSNumber to NSString attribute using lightweight migration in objective C. Version 0 enter image description here

Version 2

enter image description here

I've changed the core data model current version to 2

enter image description here

Since it won't resolved in light weight migration I tried with CoreDataMapping Model and NSEntity migration policy like below. enter image description here

Have created a subclass of NSEntityMigrationPolicy and tried the below code

@interface SampleMigrationV1toV2 : NSEntityMigrationPolicy

@end

#import "SampleMigrationV1toV2.h"

@implementation SampleMigrationV1toV2

- (BOOL)createDestinationInstancesForSourceInstance:(NSManagedObject *)sInstance entityMapping:(NSEntityMapping *)mapping manager:(NSMigrationManager *)manager error:(NSError **)error
{
    NSManagedObject *newObject = [NSEntityDescription insertNewObjectForEntityForName:[mapping destinationEntityName] inManagedObjectContext:[manager destinationContext]];

    // Copy all the values from sInstance into newObject, making sure to apply the conversion for the string to int when appropriate. So you should have one of these for each attribute:
    [newObject setValue:[sInstance valueForKey:@"number"] forKey:@"number"];

    [manager associateSourceInstance:sInstance withDestinationInstance:newObject forEntityMapping:mapping];
    return YES;
}
@end

In persistent coordinator I've changed the NSInferMappingModelAutomaticallyOption to NO like below,

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

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

    NSString *storePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent:@"CoreDataMigrationPolicty.sqlite"];

    NSURL *storeUrl = [NSURL fileURLWithPath:storePath];

    NSMutableDictionary *options = [[NSMutableDictionary alloc] init];
    [options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
    [options setObject:[NSNumber numberWithBool:NO] forKey:NSInferMappingModelAutomaticallyOption];

    NSError *error = nil;
    persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error])
    {
        //NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }

    return persistentStoreCoordinator;
}

After doing all these thing I'm getting error like " Error Domain=NSCocoaErrorDomain Code=134110 "(null)" UserInfo={NSUnderlyingException=Couldn't create mapping policy for class named (CoreDataMigrationPolicty.SampleMigrationV1toV2)} with userInfo dictionary

Mapping model is not being created/called. Is it correct approach to change the attribute datatype in core data. Is there any other way to fix this issue without crash/reinstalling the app.

Mohan Kumar
  • 334
  • 1
  • 4
  • 10
  • Lightweight migration is the best way if you want to add attribute in app with filled database. But you are not able to change data type because there are different internal sqlite approaches to store strings and numbers and obviously they are could not be mapped. If the data is not important or app haven't sent to production yet, you can create new managed objects from updated model, and create new .sqlite DB instead old one. Otherwise just add another entity using migration called something like string_number, and write code, that will copy existing values from number to string_number – Nikolay Tabunchenko Oct 23 '17 at 21:29

1 Answers1

1

Finally I found mistake what I did from this answer. Core Data Migration: Attribute Mapping Value Expression

The problem is with the expression I mentioned in the mapping model attribute. Syntax is FUNCTION($entityPolicy, "convertNumberToString:" , $source.number) and the function definition is like

#import "SampleMigrationV1toV2.h"

@implementation SampleMigrationV1toV2

-(NSString *)convertNumberToString:(NSNumber *)number{
    return  [number stringValue];
}
@end

Mention Custom policy name(i.e.SampleMigrationV1toV2) on clicking Entity Mapping SampleToSample in

Enter the expression "FUNCTION($entityPolicy, "convertNumberToString:" , $source.number)" on clicking the attribute you want to migrate

FUNCTION($entityPolicy, "convertNumberToString:" , $source.number) :

$entityPolicy get the corresponding MappingPolicy (i.e SampleMigrationV1toV2) as we mentioned in the EntityMapping "SampleToSample" and the function "convertNumberToString:" migrate the number to string by taking the input value $source.Number

Mohan Kumar
  • 334
  • 1
  • 4
  • 10