0

I am having an app which use core data which supports both ios 9 as well ios 10.I am using xcode 8.2.1 for developing this project. The AppDelegate file have method for to get ManagedObjectContext when app runs on ios 10 but, how do i get it when app works on ios 9. I tried to google but nothing helped much. Any help !

the code i use to get ManagedObjectContext is here :

 NSManagedObjectContext *context = ((AppDelegate*)[[UIApplication sharedApplication] delegate]).persistentContainer.viewContext;
kishan
  • 203
  • 1
  • 6
  • 15

3 Answers3

12

If your app supports both ios 9 as well ios 10 then you can use #available attribute to check current running version and run code accordingly because NSPersistentContainer is only available from iOS 10 and onwards.

In Swift 3

// MARK: - Core Data Saving support

    func saveContext () {

        let coreDataFileName = "Use your core data file name"

        if #available(iOS 10.0, *) {
            let context = persistentContainer.viewContext
            if context.hasChanges {
                do {
                    try context.save()
                } catch {
                    // Replace this implementation with code to handle the error appropriately.
                    // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                    let nserror = error as NSError
                    fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
                }
            }
        }else {

            if managedObjectContext.hasChanges {
                do {
                    try managedObjectContext.save()
                } catch let error as NSError {
                    print("Ops there was an error \(error.localizedDescription)")
                    abort()
                }
            }

        }
    }

    // Applications default directory address
    lazy var applicationDocumentsDirectory: NSURL = {
        let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
        return urls[urls.count-1] as NSURL
    }()
    lazy var managedObjectModel: NSManagedObjectModel = {
        // 1
        let modelURL = Bundle.main.url(forResource: coreDataFileName, withExtension: "momd")!
        return NSManagedObjectModel(contentsOf: modelURL)!
    }()
    lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
        let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
        let url = self.applicationDocumentsDirectory.appendingPathComponent("\(coreDataFileName).sqlite")
        do {
            // If your looking for any kind of migration then here is the time to pass it to the options
            try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: nil)
        } catch let  error as NSError {
            print("Ops there was an error \(error.localizedDescription)")
            abort()
        }
        return coordinator
    }()

    lazy var managedObjectContext: NSManagedObjectContext = {
        //    // Returns the managed object context for the application (which is already bound to the persistent store coordinator for the
        //    application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to
        //    fail.
        let coordinator = self.persistentStoreCoordinator
        var context = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
        context.persistentStoreCoordinator = coordinator
        return context
    }()

In Objective - C In AppDelegate.m

#pragma mark - Core Data Saving support

@synthesize managedObjectContext = _managedObjectContext;
@synthesize managedObjectModel = _managedObjectModel;
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
@synthesize persistentContainer = _persistentContainer;

- (NSURL *)applicationDocumentsDirectory {
    // The directory the application uses to store the Core Data store file. This code uses a directory named "Your Bundle Indentifier" in the application's documents directory.
    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}

- (NSManagedObjectModel *)managedObjectModel {
    // The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
    if (_managedObjectModel != nil) {
        return _managedObjectModel;
    }
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Use your core data file name" withExtension:@"momd"];
    _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
    return _managedObjectModel;
}

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
    // The persistent store coordinator for the application. This implementation creates and returns a coordinator, having added the store for the application to it.
    if (_persistentStoreCoordinator != nil) {
        return _persistentStoreCoordinator;
    }

    // Create the coordinator and store

    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"Use your core data file name.sqlite"];
    NSError *error = nil;
    NSString *failureReason = @"There was an error creating or loading the application's saved data.";
    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
        // Report any error we got.
        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
        dict[NSLocalizedDescriptionKey] = @"Failed to initialize the application's saved data";
        dict[NSLocalizedFailureReasonErrorKey] = failureReason;
        dict[NSUnderlyingErrorKey] = error;
        error = [NSError errorWithDomain:@"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict];
        // Replace this with code to handle the error appropriately.
        // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }

    return _persistentStoreCoordinator;
}


- (NSManagedObjectContext *)managedObjectContext {
    // Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.)
    if (_managedObjectContext != nil) {
        return _managedObjectContext;
    }

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (!coordinator) {
        return nil;
    }
    _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    [_managedObjectContext setPersistentStoreCoordinator:coordinator];
    return _managedObjectContext;
}

#pragma mark - Core Data Saving support

- (void)saveContext {

    //Check current version.
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 10.0){

        NSManagedObjectContext *context =_persistentContainer.viewContext;

        if (context != nil) {
            NSError *error = nil;
            if ([context hasChanges] && ![context save:&error]) {
                // Replace this implementation with code to handle the error appropriately.
                // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
                abort();
            }
        }
    }else{
        NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
        if (managedObjectContext != nil) {
            NSError *error = nil;
            if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
                // Replace this implementation with code to handle the error appropriately.
                // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
                abort();
            }
        }
    }
}

In AppDelegate.h use

#pragma mark - Core data for messages vriable
@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
@property (readonly, strong) NSPersistentContainer *persistentContainer;

- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;
Nikhlesh Bagdiya
  • 4,316
  • 1
  • 19
  • 29
2

As Jon Rose mentioned, NSPersistentContainer is only available from iOS 10. Best solution if you still need your app working in previous versions is use the old Core Data Stack, here you have an excellent blog explaining the differences between both methods: Core Data in ios10

The other solution would be use the #available attribute in swift to execute the Core Data Stack or the NSPersistentContainer, here you have the documentation about this: Swift Attributes

  • hey @Lucas i am not familiar with swift any link if you have for such tutorial in objective c ? well any way thanks for help – kishan Feb 23 '17 at 06:38
  • Yes of course! Here you have the link to the #available equivalent in Objective-C: http://stackoverflow.com/questions/7848766/how-can-we-programmatically-detect-which-ios-version-is-device-running-on – Lucas Fernández Aragón Feb 23 '17 at 15:25
  • And unfortunately, there is no tutorial for NSPersistentContainer in Objective-C, here you have the documentation, best you can do is follow the tutorial in swift and try to replicate it with objective. https://developer.apple.com/reference/coredata/nspersistentcontainer?language=objc – Lucas Fernández Aragón Feb 23 '17 at 15:28
1

NSPersistentContainer is only available from iOS 10 and onwards. If you need to support lower system then you can't use it. You have to setup your own core data stack without NSPersistentContainer.

Jon Rose
  • 8,373
  • 1
  • 30
  • 36
  • any help how can i implement this, i have tried one but, it didn't helped http://stackoverflow.com/questions/37956720/how-to-create-managedobjectcontext-using-swift-3-in-xcode-8 – kishan Feb 22 '17 at 13:24
  • You can try https://github.com/inspace-io/INSPersistentContainer. I looked at the code and it is not bad, but he is lacking an operation queue for the writes. – Jon Rose Feb 22 '17 at 13:33