mmklug
mmklug

Reputation: 2432

CoreData: annotation: Failed to load optimized model at path (Xcode 11 -> iOS 12)

When building and running a Core Data project (created with Xcode 10) using Xcode 11 (beta 3) on an iOS 12 device, I get the warning:

CoreData: annotation: Failed to load optimized model at path '/var/containers/Bundle/Application/7908B3F7-66BC-4931-A578-6A740CBFB37D/TestOMO.app/TestOMO.momd/TestOMO.omo'

There is no warning if

My app seems to work fine and there are no crashes, so I am not sure how seriously to take this warning. Nonetheless I would surely prefer to get rid of it.

There are many posts related to this Core Data annotation, but most are either related to Google Maps or are unanswered.

I have created a new project to eliminate other causes for the issue related to my own project and to make it easy to reproduce as follows:

  1. Create a new project using Xcode 10 (Single View App, Use Core Data)
  2. In AppDelegate.swift, add print ("psc = (persistentContainer)") to func application(_ , didFinishLaunchingWithOptions:) (just to force lazy var initialisation)
  3. Build and run on an iOS12 device: no issues
  4. Open the same project in Xcode 11, build and run on an iOS13 device: no issues
  5. Sill in Xcode 11, build and run on an iOS12 device: you will get the warning quoted above

Cleaning the build folder or deleting derived data is of no help.

Upvotes: 13

Views: 3785

Answers (2)

bauerMusic
bauerMusic

Reputation: 6176

Since older code can often be in Objective C, here's an ObjC version (this is sourced on the answer from @Lobo):

- (NSPersistentContainer *)samplePersistentContainer {
    // The persistent container for the application. This implementation creates and returns a container, having loaded the store for the application to it.
    @synchronized (self) {

        if (_persistentContainer == nil) {

            NSString *modelName = @"ModelName";

            if (@available(iOS 13, *)) {

                _persistentContainer = [NSPersistentContainer persistentContainerWithName: modelName];
                [_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
                    if (error != nil) {
                        NSLog(@"Unresolved error %@, %@", error, error.userInfo);
                        abort();
                    }
                }];

            } else {

                NSString *modelURLPath = [[NSBundle mainBundle] pathForResource: modelName ofType: @"momd"];

                NSURL *modelURL = [NSURL fileURLWithPath: modelURLPath];

                NSURL *versionInfoURL = [modelURL URLByAppendingPathComponent: @"VersionInfo.plist"];

                NSDictionary *versionInfoNSDictionary = [NSDictionary dictionaryWithContentsOfURL: versionInfoURL];

                NSString *version = versionInfoNSDictionary[@"NSManagedObjectModel_CurrentVersionName"];

                modelURL = [modelURL URLByAppendingPathComponent:[NSString stringWithFormat: @"%@.mom", version]];

                NSManagedObjectModel *mod = [[NSManagedObjectModel alloc] initWithContentsOfURL: modelURL];

                _persistentContainer = [NSPersistentContainer persistentContainerWithName: modelName managedObjectModel: mod];
            }
        }
    }

    return _persistentContainer;
}

Upvotes: 1

mmklug
mmklug

Reputation: 2432

I was able to solve the issue thanks to the hint in @ChaitanyaKhurana's comment above.

Here is the swift code I have implemented, replacing the original single line

let container = NSPersistentContainer(name: "ModelName")

Part of the code is needed to retrieve the model version string (from the .plist file located in the .momd package) in order to avoid having to update the code each time there is a new model version.

Please also note that the new/alternative code only executes on iOS versions prior to 13.0 as there is not issue on iOS 13.

let modelName = "ModelName"

var container: NSPersistentContainer!

if #available(iOS 13.0, *) {
    container = NSPersistentContainer(name: modelName)
} else {
    var modelURL = Bundle(for: type(of: self)).url(forResource: modelName, withExtension: "momd")!
    let versionInfoURL = modelURL.appendingPathComponent("VersionInfo.plist")
    if let versionInfoNSDictionary = NSDictionary(contentsOf: versionInfoURL),
        let version = versionInfoNSDictionary.object(forKey: "NSManagedObjectModel_CurrentVersionName") as? String {
        modelURL.appendPathComponent("\(version).mom")
        let managedObjectModel = NSManagedObjectModel(contentsOf: modelURL)
        container = NSPersistentContainer(name: modelName, managedObjectModel: managedObjectModel!)
    } else {
        //fall back solution; runs fine despite "Failed to load optimized model" warning
        container = NSPersistentContainer(name: modelName)
    }
}

Upvotes: 10

Related Questions