This post is part of my collection: Swift 2 – For Beginners.
Core Data is a persistence framework provided by Apple. In this example we will see how to use it in our iOS application. First we will see how to create our data model and then how to perform the following basic operations:
- Create
- Get by Id
- Get all and Get applying a predicate
- Update
- Remove
How to create our data model
A data model consist of a group of entities. The concept of entity in Core Data is similar to the concept of table in SQL. Each entity can have attributes in the same way that a table can have columns.
To create a new entity you need a project with Core Data included. Then go to your xdatamodel file and click “Add Entity”, “Add Attribute” to configure it.
To keep the example simple our data model will have one entity with two attributes. A Person with name and age:
Person
-name: string
-age: integer
To create a class that represent our data model click on “Editor” > “Create NSManagedObject Subclass…”.
It should create a class and an extension representing our entity “Person”. To that class we will only add a static field with the entity name, we will use it later to avoid magic strings:
extension Person { @NSManaged var name: String? @NSManaged var age: NSNumber? }
class Person: NSManagedObject { // Add this line, the string must be equal to your class name static let entityName = "Person" }
managedObjectContext
Before writing code to make our basic operations it is important to know what the managedObjectContext is.
When the project has Core Data Xcode add a bunch of code to our AppDelegate.swift. A piece of that code is the managedObjectContext. This is the object that we need to access the data model. We can get it in our controller with this line of code:
let context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
To save our changes we always have to call context.save(). It can throw an exception so we have to make the call in a do.. catch.. block:
// Saves all changes func saveChanges(){ do{ try context.save() } catch let error as NSError { // failure print(error) } }
Now we are ready to write our basic functions to access the data model:
Create
// Creates a new Person func create(name: String, age: NSNumber) -> Person { let newItem = NSEntityDescription.insertNewObjectForEntityForName(Person.entityName, inManagedObjectContext: context) as! Person newItem.name = name newItem.age = age return newItem }
GetById
// Gets a person by id func getById(id: NSManagedObjectID) -> Person? { return context.objectWithID(id) as? Person }
Get
Now we will see how to get all entities and how to get all entities applying a NSPredicate to our query.
// Gets all with an specified predicate. // Predicates examples: // - NSPredicate(format: "name == %@", "Juan Carlos") // - NSPredicate(format: "name contains %@", "Juan") func get(withPredicate queryPredicate: NSPredicate) -> [Person]{ let fetchRequest = NSFetchRequest(entityName: Person.entityName) fetchRequest.predicate = queryPredicate do { let response = try context.executeFetchRequest(fetchRequest) return response as! [Person] } catch let error as NSError { // failure print(error) return [Person]() } }
Our get all function will be a call to the previous function. The predicate will be a true predicate, to return all objects in our data model.
// Gets all. func getAll() -> [Person]{ return get(withPredicate: NSPredicate(value:true)) }
Update
// Updates a person func update(updatedPerson: Person){ if let person = getById(updatedPerson.objectID){ person.name = updatedPerson.name person.age = updatedPerson.age } }
Remove
// Deletes a person func delete(id: NSManagedObjectID){ if let personToDelete = getById(id){ context.deleteObject(personToDelete) } }
Complete example:
This class puts all the functions that we have seen before together, we can call it PersonService.
import CoreData class PersonService{ var context: NSManagedObjectContext init(context: NSManagedObjectContext){ self.context = context } // Creates a new Person func create(name: String, age: NSNumber) -> Person { let newItem = NSEntityDescription.insertNewObjectForEntityForName(Person.entityName, inManagedObjectContext: context) as! Person newItem.name = name newItem.age = age return newItem } // Gets a person by id func getById(id: NSManagedObjectID) -> Person? { return context.objectWithID(id) as? Person } // Gets all. func getAll() -> [Person]{ return get(withPredicate: NSPredicate(value:true)) } // Gets all that fulfill the specified predicate. // Predicates examples: // - NSPredicate(format: "name == %@", "Juan Carlos") // - NSPredicate(format: "name contains %@", "Juan") func get(withPredicate queryPredicate: NSPredicate) -> [Person]{ let fetchRequest = NSFetchRequest(entityName: Person.entityName) fetchRequest.predicate = queryPredicate do { let response = try context.executeFetchRequest(fetchRequest) return response as! [Person] } catch let error as NSError { // failure print(error) return [Person]() } } // Updates a person func update(updatedPerson: Person){ if let person = getById(updatedPerson.objectID){ person.name = updatedPerson.name person.age = updatedPerson.age } } // Deletes a person func delete(id: NSManagedObjectID){ if let personToDelete = getById(id){ context.deleteObject(personToDelete) } } // Saves all changes func saveChanges(){ do{ try context.save() } catch let error as NSError { // failure print(error) } } }
How to use the service:
// Create an instance of the service. let context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext let personService = PersonService(context: context) // Create let juanCarlos = personService.create("Juan Carlos", age: 52) // Read all var people : [Person] = personService.getAll() // Read by id let firstPerson = personService.getById(people[0].objectID)! // Update firstPerson.name = "Juan Carlos Sanchez" personService.update(firstPerson) // Delete personService.delete(firstPerson.objectID)
Hi Juan, great post, thank you.
I have 2 questions…
1.) I get a compile error with my PersonService class:
class PersonService{
var context: NSManagedObjectContext <- error says "Stored property 'context' requires an initial value or should be @NSManaged"
2.) When do we call saveChanges() when using this PersonService?
Thanks again!
LikeLike
Hey, Have you got any solution for first question.?
LikeLike
Hi,
1) Make sure that NSManagedObject is not a base class of PersonService. You can find my PersonService class here: https://gist.github.com/softwarejc/99fb60eef461b356e0a3
2) The idea of saveChanges is that you can do changes to your context and save to the database when you want.
I hope that help you!
Thank you for your comment and have fun with Swift!
LikeLike
How does one actually access the data in their attributes using the get functions though?
LikeLike
Thank you for a great post.
LikeLike
Its a good and very useful tutorial. If you could update it for Swift 3 and XCode 8, it would be great.
LikeLike
Thanks, it helps me a lot, I just wonder if there multiple model, and their fields are different, I should create many services to meet it , or is there good solutions?
LikeLike
Really a great tutorial all at one Place , Really Thanks Best Core data Tutorial I had seen , Any Updated link for core Data relationships ? if yes, Would love to check out
LikeLike