What’s new in Core Data Swift 3.0

Datetime:2016-08-23 04:14:03          Topic: Swift           Share

Apple has made some big changes in Core Data and taken the burdens from our shoulders.

In this blog post we will be comparing Core Data with Xcode 7.3.1 vs new Core Data with Xcode 8 beta to see if it has become any easier to use Core Data.

If we are creating a new application with Single View Application or Master-Detail Application we can check the Use Core Data option and Xcode will automatically generate some boilerplate code in AppDelegate class. But what if you’re creating a Tabbed Application, Page- Based Application, Game, or even planning to add Core Data to an existing project? We can create a new Single View Application or Master-Detail Application and then copy all the code for core data from AppDelegate and paste it in our current project’s AppDelegate class. In both cases the AppDelegate class will be full with boilerplate code which are quite some lines of code.

An even better solution is to create a new class for the Core Data and put all the boilerplate code there. Then modify it as you wish, and you can use that class in all of your projects. Having a separate class will make your life easier in case you want to perform any kind of Migration in future releases of your app. Or even if you have an extension where both your container app and extension can access this class.

Here I Have created a class called CoreDataStack.swift and moved all the Core Data code from AppDelegate to CoreDataStack.swift

import CoreData
class CoreDataStack {
    // Applications default directory address
    lazyvar applicationDocumentsDirectory: NSURL = {
        let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
        return urls[urls.count-1]
}()
lazyvar managedObjectModel: NSManagedObjectModel = {
        // 1
        let modelURL = NSBundle.mainBundle().URLForResource("Supercars", withExtension: "momd")!
        return NSManagedObjectModel(contentsOfURL: modelURL)!
}()
lazyvar persistentStoreCoordinator: NSPersistentStoreCoordinator = {
        let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
        let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("SuperCars.sqlite")
        do {
            // If your looking for any kind of migration then here is the time to pass it to the options
            try coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil)
        } catch let  error as NSError {
          print("Ops there was an error \(error.localizedDescription)")
          abort()
        }
        return coordinator
}()
 
lazyvar managedObjectContext: NSManagedObjectContext = {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the
application.) Thispropertyis optionalsincetherearelegitimateerrorconditionsthatcouldcausethecreationofthecontextto
fail.
        let coordinator = self.persistentStoreCoordinator
        var context = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
        context.persistentStoreCoordinator = coordinator
        return context
}()
// if there is any change in the context save it
func saveContext() {
        if mangagedObjectContext.hasChanges {
            do {
                try managedObjectContext.save()
            } catch let error as NSError {
                print("Ops there was an error \(error.localizedDescription)")
                abort() 
      }
    } 
  }
}

1. For Managed Object Model name Apple uses your application name by default but you can name it anything you like.

Keep in mind that you have to name your Data Model the same as your Managed Object Model for this example the name should be (Supercars.xcdatamodeld)

Ok now let’s see how do we use this class in AppDelegate.swift First we have to import core data.

import CoreData

Inside AppDelegate class we create a new lazy var instance of this class

lazyvar coreDataStack = CoreDataStack()

However this blog post is not about Swift properties but you might be wondering why lazy var. we have seen lazy property in front of var many times now. Can we not just write the same line of code without lazy property like this

var coreDataStack = CoreDataStack()

Actually we can, but lets see what Apple says about it and why it’s good to use it in this case.

A lazy stored property is a property whose value is not calculated until the first time it is used.

Ok enough talked about lazy property. Now let’s see how we can call save function in applicationWillTerminate function in AppDelegate class.

func applicationWillTerminate(application: UIApplication) {
    coreDataStack.saveContext()
}

Now if we look at our AppDelegate class it’s a lot more clean and we can use CoreDataStack class in as many projects as we like.

But wait This post is not about refactoring we want to see what’s new in Core Data

I can say that Apple is try to tie our hands up and don’t want us to type a lot. Here is the same CoreDataStack class created in Xcode 8 beta and Swift 3 I think even a none programmer can see the big difference by counting lines of code in both classes.

import CoreData
class CoreDataStack {
    lazyvar persistentContainer: NSPersistentContainer = {
        let container = NSPersistentContainer(name: "Supercars")
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
        if let error = error {
        fatalError("Unresolved error \(error), \(error.userInfo)")
      }
  })
      return container
}()
 
func saveContext() {
    let context = persistentContainer.viewContext
    if context.hasChanges {
        do {
              try context.save()
            } catch let error as NSError {
                fatalError("Unresolved error \(error), \(error.userInfo)")
      }
    }
  } 
}

Yes this is all the code in our new CoreDataStack class. You Create a persistentContainer it takes care of creating and loading your Managed Object Model. Everything is now encapsulated inside a single NSPersistentContainer class.

You may ask for few lines of code why I have created a class you can leave it in your AppDelegate class it’s totally fine. I think having it in a separate class will help you in the future for example if you want to make changes in your Data Model then you have to deal with Migration. Also your AppDelegate will be a few lines less and clean.

So is it all the changes in this new update for Core Data? The answer is NO.

let’s see how can we get an entity and add an item to it in current version of Core Data and Xcode 7.3 of course Swift 2.2

let entity = NSEntityDescription.entityForName("Car", inManagedObjectContext: context)
let car = NSManagedObject(entity: entity!, insertIntoManagedObjectContext: context)
car.setValue("Ferrari", forKey: “name”)

We can generate NSManagedObject subclass for our entity in that case the code will be like this

let entity = NSEntityDescription.entityForName("Car", inManagedObjectContext: context)
let car = NSManagedObject(entity: entity!, insertIntoManagedObjectContext: context) as! Car
car.name = “Ferrari"

Generating NSManagedObject subclass for Entity is useful thing to do. It helps you eliminate key-value coding which can lead to any kind of mistyping, misspelling also gives you ability to use dot notation and so on. But you have to know that everything comes with a price. You have to generate NSManagedObject classes manually for your entities. Xcode will add 2 new files to your source tree per entity. Think if you have 5 entities then Xcode will add 10 new .swift files to your source tree not only that every time you make a change to any of your entity you have to regenerate your NSManagedObject subclass for that entity.

Now let’s see how can we get the entity and add an item to it in Xcode 8 and swift 3

let car = Car(context: context)
car.name = “Ferrari”

let car = Car ( context : context )

car . name =Ferrari

That’s it. No more key-value coding, No more type casting, You don’t have to generate NSManagedObject subclasses yourself as soon as you add an entity to your Data Model build your project and Xcode 8 will happily take care of all those subclasses for you. Oh and your source tree will be clean as well.

I tried to quickly point a few important changes but there are a lot which has been changed. If you’re interested to know more watch WWDC 2016 What’s new in Core Data video.

https://developer.apple.com/videos/play/wwdc2016/242/





About List