Load a previous model version
Asked Answered
M

5

18

I am loading a NSManagedObjectModel model with the initWithContentsOfURL: constructor like this:

NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"MyDocument" withExtension:@"momd"];
NSManagedObjectModel *mom = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];

However this only gives me access to the latest/current version of a model. Is it posible to load previous versions with the same momd file? how?

Mexicali answered 23/6, 2012 at 10:27 Comment(0)
H
36

Actually you can load an older version with:

- (NSManagedObjectModel *)managedObjectModelForVersion:(NSString *)version
{
        NSURL *modelURL = [[NSBundle mainBundle] URLForResource:[NSString stringWithFormat:@"AppModel.momd/AppModel %@",version] withExtension:@"mom"];
        NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
        return model;
 }

Just replace AppModel with your model name.

I'm using this to get myself out of a sticky manual migration situation involving iCloud. Searched high and low and couldn't find this anywhere.

Heger answered 12/9, 2012 at 14:59 Comment(1)
fyi on my version (7.1) the version .mom(s) are in a file with the same name as the version (so @".../%@", version instead of @"/.../AppModel %@", version)Duffel
S
4

If you just want to load the version of the model that's compatible with a particular existing store try:

NSError *error = nil;
NSDictionary *storeMetadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType 
                                                                                         URL:storeURL 
                                                                                       error:&error];
NSManagedObjectModel *oldManagedObjectModel = [NSManagedObjectModel mergedModelFromBundles:[NSArray arrayWithObject:[NSBundle mainBundle]] 
                                                                          forStoreMetadata:storeMetadata];

Note that if you use XCode version identifiers for your data model versions, the persistent store's current version identifiers are accessible through the NSStoreModelVersionIdentifiersKey entry in the store metadata dictionary.

As far as loading a particular arbitrary version is concerned, the mom files are typically located under the momd directory in your app's bundle, so you could enumerate them using NSFileManager. I believe to find one with a particular version identifier you would have to use NSManagedObjectModel's initWithContentsOfURL: initializer and then inspect the versionIdentifiers property, or use the isConfiguration:compatibleWithStoreMetadata: instance method to determine compatibility.

Samanthasamanthia answered 5/9, 2012 at 15:46 Comment(1)
And check for a nil storeMetadata in which case you haven't got an existing database so need to create one!Terrazzo
S
1

Made the solution offered by @Schoob into a category, because they rock.

@interface NSManagedObjectModel (version)
+ (NSManagedObjectModel *)modelFromBundle:(NSBundle *)bundle name:(NSString *)modelName version:(NSString *)version;
@end

@implementation NSManagedObjectModel (version)
+ (NSManagedObjectModel *)modelFromBundle:(NSBundle *)bundle name:(NSString *)modelName version:(NSString *)version
{
    if(!bundle)
        bundle = [NSBundle mainBundle];

    NSString *resource = [[modelName stringByAppendingPathExtension:@"momd"] stringByAppendingPathComponent:version];
    NSURL *modelURL = [bundle URLForResource:resource withExtension:@"mom"];
    NSAssert(modelURL,@"Unable to find MOM - %@",resource);
    NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
    NSAssert(model,@"Unable to load MOM at URL- %@",modelURL);
    return model;
}
@end
Sanborne answered 29/5, 2014 at 23:9 Comment(0)
K
0

Swift version. Replace file name.

import CoreData

extension NSManagedObjectModel
{
    class func model(forVersion version: Int) -> NSManagedObjectModel?
    {
        if let fileUrl = Bundle.main.url(forResource: "Model.momd/Model \(version)", withExtension: "mom")
        {
            return NSManagedObjectModel(contentsOf: fileUrl)
        }
        return .none
    }
}
Kyleekylen answered 7/2, 2017 at 9:17 Comment(0)
L
-2

No, it is not foreseen that this is possible. I deduce that from the NSManagedObjectModel documentation, where it says discussing the property versionIdentifiers:

This value is meant to be used as a debugging hint to help you determine the models that were combined to create a merged model.

So it does not seem you are supposed to use previous model versions for your program logic.

Landman answered 23/6, 2012 at 11:45 Comment(2)
how do you do normally a custom migration? in order to temporally solve this I make a copy of the folder for my data model (which contains all the versions again) and set as default version the older one I want to support. That way I can build the old and new instances of NSManagedObjectModel that I need for NSMigrationManagerMexicali
I don't agree with this. Please view my answer.Heger

© 2022 - 2024 — McMap. All rights reserved.