CoreData basics (Xcode 9 + Swift 4)

Krzysztof Kempiński
kkempin’s dev blog
5 min readNov 22, 2017
CoreData Basics

In that article I will show you some basics of CoreData framework, which is a tool for iOS, macOS, tvOS and watchOS platforms to manage objects modeling, lifecycle and persistence. But I’ll not try to summarise or cover every point from the documentation. You can do it yourself here — https://developer.apple.com/documentation/coredata . Instead, I will show you how to model your objects and how to run queries if you want to read or write something.

A sample project that we will be creating will be build with Xcode 9 and Swift 4.

Let’s get our hands dirty!

New project in Xcode

First, let’s create a new project and let’s select “Use Core Data”. Although you can add that framework for your existing project, it’s easier to add it from that place as everything will be wired up already for you.

Once the project is created, you will see a file like CoreDataTest.xcdatamodeld added.

When you click it, you will see a tool that allows you to configure entities which represents data models. You can define few things for each entity there but for us Attributes and Relationships will be most important.

Configuring User entity

Let’s add a new entity called User (to change it’s name once you’ve clicked Add Entity button, click the name of a newly added entity on top twice and type in your name).

Now, let’s add a few attributes that will define a schema of our new entity : email — String, name — String, date_of_birth — Date, number_of_children — Integer 16

Configuring Car entity

Same way let’s add a new entity called Car that will include attributes: model — String, year — Integer 16. But now let’s add a relationship between cars and users. To do it we will add a relationship, represented by user, from that point to User entity. Than you have to get back to User entity and set relationship with Car. After that on Car you can set an inverse relationship to User.

Configuring User -> Car relationship and Car -> User inverse relationship
User -> Car relationship needs to be of type “to many”

Last step in the editor is to configure proper type of relationship. By default it’s “To one” which is one-to-one relation. In our case, a user can have many cars, so let’s change the type for the relationship “cars” on User to “To Many”.

OK, so we are done with modeling. Now, let’s see how to create a new object, persist in the storage and read it after that. CoreData uses a SQLite database as the persistent store.

Before we do this you need to create an object called managed object model, which describes the way Core Data represents data on disk. You will use that object to send requests to it so it can hit the database.

Open ViewController.swift and import CoreData module:

import CoreData

Now, let’s create a managed object model:

guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }let managedContext = appDelegate.persistentContainer.viewContextlet userEntity = NSEntityDescription.entity(forEntityName: "User", in: managedContext)!

userEntity is our managed object model in managed context so let’s create our first user:

let user = NSManagedObject(entity: userEntity, insertInto: managedContext)user.setValue("John", forKeyPath: "name")
user.setValue("john@test.com", forKey: "email")
let formatter = DateFormatter()
formatter.dateFormat = "yyyy/MM/dd"
let date = formatter.date(from: "1990/10/08")
user.setValue(date, forKey: "date_of_birth")
user.setValue(0, forKey: "number_of_children")

We’ve created a new object user and we’ve set up values for each of the attribute that we’ve defined before.

John has two cars:

let carEntity = NSEntityDescription.entity(forEntityName: "Car", in: managedContext)!let car1 = NSManagedObject(entity: carEntity, insertInto: managedContext)
car1.setValue("Audi TT", forKey: "model")
car1.setValue(2010, forKey: "year")
car1.setValue(user, forKey: "user")
let car2 = NSManagedObject(entity: carEntity, insertInto: managedContext)
car2.setValue("BMW X6", forKey: "model")
car2.setValue(2014, forKey: "year")
car2.setValue(user, forKey: "user")

We’ve created a managed object model for a car (carEntity) and we’ve added BMW X6 and Audi TT. What is important here is that we’ve connected these cars with John using a relationship defined above (car1.setValue(user, forKey: “user”)).

To send everything to the underlying SQLite layer and store it we need to do one last thing:

do {
try managedContext.save()
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}

We are calling save() on managed context. In terms of any failure, we are printing some useful error information.

Great! So we have data stored. Now let’s see how we can read it. First, let’s create a special object that will represent our request to the database:

let userFetch = NSFetchRequest<NSFetchRequestResult>(entityName: "User")

Let’s work on our request. We want to fetch just a one record:

userFetch.fetchLimit = 1

and only when a name is “John”:

userFetch.predicate = NSPredicate(format: "name = %@", "John")

Moreover, we want to sort by an email address with ascending order:

userFetch.sortDescriptors = [NSSortDescriptor.init(key: "email", ascending: true)]

Let’s execute the query:

let users = try! managedContext.fetch(userFetch)

Now we can pick the first result and print how many cars he has :)

let john: User = users.first as! Userprint("Email: \(john.email!)")
let johnCars = john.cars?.allObjects as! [Car]
print("has \(johnCars.count)")

CoreData framework has a lot more, like data migrations or background tasks but for a day to day work, you will rather use the basics I’ve showed you above.

The codebase of that sample project can be cloned from https://github.com/kkempin/CoreDataTest

Want to know first about new articles from that blog?

Subscribe to my newsletter now! — http://eepurl.com/cVPm_v

If you like this article and consider it useful for you, please support it with 👏.

--

--

kkempin’s dev blog
kkempin’s dev blog

Published in kkempin’s dev blog

Dev and life blog. Thoughts about programming, design patterns, Ruby and life.

Krzysztof Kempiński
Krzysztof Kempiński

Written by Krzysztof Kempiński

IT expert. Ruby on Rails/iOS/Elixir programmer. Blogger. Podcaster.

Responses (14)