0

I'm using CoreData to manage my offline storage in my app. The data of the offline storage is saved in an custom NSObject as a transformable in the xcdatamodel.

My current version in the app (v1.0) is storing the Navigation class.

I needed to rename the Navigation class to fight some name space problems in another target of my code base.

In Version 2.0 the app is crashing because when I'm searching the CoreData store the NSKeyedUnarchiver is failing because of the missing Navigation class.

What's the best approach to migrate my current CoreData store to fight this issue?

I tried something like this:

NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"OfflineStorage"];
request.fetchLimit = 1;
request.predicate = [NSPredicate predicateWithFormat:@"storageID = 1"];

NSError *error;
NSArray *result;
@try {
    result = [context executeFetchRequest:request error:&error];
}
@catch (NSException *exception) {
    if([exception.name isEqualToString:NSInvalidUnarchiveOperationException]) {
            NSFetchRequest *deleteRequest = [request copy];
            deleteRequest.resultType = NSManagedObjectIDResultType;
            deleteRequest.includesPropertyValues = NO;
            deleteRequest.propertiesToFetch = @[];

            NSArray *deleteResult = [context executeFetchRequest:request error:&error];
            if(deleteResult.count) {
                [context performBlockAndWait:^{
                    [context deleteObject:deleteResult.firstObject];
                    [context save:nil];
                }];
            }
    }
}

I though I would be smart to catch the exception and try only to fetch the ObjectID to delete the corrupt data in my store. But it's not working…

mariusLAN
  • 1,195
  • 1
  • 12
  • 26

1 Answers1

1

Did you add a new version to your model where you renamed that transformable class as well?

Did you try to do your own migration and rename the transformer for the transformable?

Here's some documentation: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreDataVersioning/Articles/Introduction.html#//apple_ref/doc/uid/TP40004399-CH1-SW1

I didn't do that myself, yet. As auto migration was enough for me by now.

Update

I'm sorry, I misunderstood your question.

The transformable is transformed by your own value transformer? If so, you could use this in the NSKeyedUnarchiver to replace the class with the old name by the new class: https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSKeyedUnarchiver_Class/index.html#//apple_ref/occ/clm/NSKeyedUnarchiver/setClass:forClassName:

Christian Beer
  • 2,027
  • 15
  • 13
  • I added a new model version. But I think the main problem is that the transformable class itself changed outside of coredata. There is no migration process because the core data thinks its all safe so far. It's only failing after fetching the property :( – mariusLAN Jul 20 '15 at 15:15
  • But you set the name of the transformable in Core Data and then register that class for that name. I wonder why the class name is relevant at all. – Christian Beer Jul 21 '15 at 09:48
  • I don't register the class name for the transformable. I just drop it there, the rest is done via NSKeyedArchiver – mariusLAN Jul 22 '15 at 11:57
  • Sorry, Marius. I forgot to request notifications for updates. So I missed your answer. – Christian Beer Jul 27 '15 at 07:06
  • I see, I totally misunderstood your question. Uups! – Christian Beer Jul 27 '15 at 07:07
  • Maybe this helps: https://developer.apple.com/library/ios/documentation/Cocoa/Reference/NSKeyedUnarchiverDelegate_Protocol/ ? – Christian Beer Jul 27 '15 at 07:08
  • Or this: https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSKeyedUnarchiver_Class/index.html#//apple_ref/occ/clm/NSKeyedUnarchiver/setClass:forClassName: – Christian Beer Jul 27 '15 at 07:09
  • I will give this a try :) – mariusLAN Jul 28 '15 at 09:19
  • The updated answer worked for me. Set the name at app start before loading anything: `[NSKeyedUnarchiver setClass:NewClassName.class forClassName:@"OldClassName"];` – danomatika Mar 04 '19 at 14:01