What you are going to create
For this tutorial, we are going to assume that the world needs another app to track your healthy food intake. It is going to be called Eat More Vegetable.
Basically, there are two options: Eat fruit (represented by the apple button) or eat vegetable (represented by the salad taco button). When you press either button, the corresponding food is added to the table view in the lower third of the screen. At the same time, the type of food you chose and the time you pressed the button are saved using Core Data.
In the upper right corner, you also have a “Remind me” button, which allows you to schedule notifications to be regularly reminded about eating something healthy. However, this app function is not covered in this written tutorial. If you want to learn how to integrate notifications into this app, you can watch my YouTube video about iOS 10 User Notifications.
Time for healthy food
Let’s start with creating a new Xcode project and choosing the Single View Application Template. I am going to call it EatMoreVegetable. For the sake of this tutorial the most important thing is that you choose Swift as the project language and that you activate “User Core Data”. After saving the project at your favorite location, we should have a look at some of the files that Xcode generated for us.
A Core Data Template
Having a look at the Navigator on the left, you should see one file that might be new to you: The
EatMoreVegetable.xcdatamodel was automatically created by Xcode, because you activated “Use Core Data” when we set up the project.
If you open that file, Xcode is going to present the Core Data Model Editor to you:
Much of Core Data’s functionality depends on the scheme you create to describe your application’s entities, their properties, and the relationships between them. Core Data uses a scheme called a managed object model.
A managed object model allows Core Data to map from records in a persistent store to managed objects that you use in your application. You can think of entities as tables in a database. Their names are also the names of the classes (subclasses of NSManagedObject), which are used to represent the entities in your application. The attributes you can add to an entity are also represented as properties in the
For our Eat More Vegetable app, we only need one entity. So, click the round plus button at the bottom of the model editor. This will create a new entity which we can click once to select it, and once more to be able to rename it. Let’s rename this entity to “Food” and create some attributes for it. To add new attributes, you can click on the “Add Attribute” Button in the lower right corner of the model editor.
We want to add an attribute called “added”, which is of the Type “Date”, and the second attribute will be called “foodType”, which should be of Type “String”:
Later, these attributes can be accessed in code, just like properties of class objects. Xcode automatically generates classes for entities added in the model editor. That is extremely convenient for us and we are going to have a look at our
NSManagedObject subclass in a moment. Before we do that however, let’s create a user interface for our app.
Build the UI
To get started, you may want to download these assets. These assets contain images that we are going to use as button images. The following short video is going to illustrate the process of creating the UI and how to connect it with the ViewController class. When you are finished, continue reading on.
The Core Data Stack
We have a data model, we also have a user interface. That means, the time of preparation is over and we can finally have a look at some code. Actually, the following code was already written for us when we activated Core Data capabilities for our project. It is located in the AppDelegate.swift file, it is the second to last function:
Since iOS 10, the creation of a Core Data Stack has been extremely simplified. We won’t go into details on the Core Data Stack itself in this tutorial, but we are going to have a look at the so called
NSPersistentContainer and the
So lets see what the code above does:
1. Since iOS 10, NSPersistentContainer is responsible for encapsulating the Core Data stack in your application, and thereby simplifies the creation and management of the Core Data stack by handling the creation of the NSManagedObjectModel, NSPersistentStoreCoordinator, and the NSManagedObject Context.
- Within the computed property “persistentContainer”, the
NSPersistentContaineris created. This loads a persistent store and deals with error handling later on. We are not going into details on that. The most important part, if you plan to integrate Core Data into an already existing app, is the initialization of NSPersistentStore with the name of the used data model file without the extension xcdatamodel (this does not necessarily have to be the App Name). In my case this is simply EatMoreVegetable:
let container = NSPersistentContainer(name: "EatMoreVegetable")
The Managed Object Context
A Core Data stack consists of multiple objects. The only one you should focus on now is an object of the type
NSManagedObjectContext. A managed object context (moc) is your most important partner when interacting with Core Data. It is like an interface between your requests (getting and adding information from and into the database). The moc sits at the top of the Core Data stack and could be simplified like this:
To access the moc, you will need to use the viewContext property of the persistent container.
How data is saved
Xcode also generated a function at the very bottom of AppDelegate.swift, called
saveContext(), because we enabled Core Data for our current project:
The function is pretty much self-explanatory. The most important aspect is that the
viewContext property of the
persistentContainer is used to get the moc, which is then used to check if there are any changes that should be persisted/saved to the database.
Common properties for Core Data driven Apps
Before we get started with working on the ViewController class, let’s make sure that we can use Core Data in the ViewController care ichnames cation. Entities, the ViewController Classlass by importing Core Data right below the import of UIKit with one simple line (Beware, we now edit the
ViewController.swift file, not
Now, we can continue adding properties that are common when it comes to apps that are driven by Core Data. We need a place to store objects we get from Core Data and we also need a way to access our moc. These are the three properties that we are going to use for that. Add them right below the class definition in the ViewController.swift file:
- This an array of Food objects. Food is a NSManagedObject subclass that was automatically generated by Xcode, based on our data model and the food entity that we added.
- Moc is going to be initialized with the moc. We get the moc by accessing the persistent conainter’s viewContext property. Our persistent container is defined in the AppDelegate class, which is why we need:
- a reference to our AppDelegate to save data and to access our moc.
To initialize the moc, we add the following line to the
Saving fruits and vegetables
You already the
addFoodToDatabase() function to the
ViewController class, when you set up the User Interface. You can add the code above to save a food item based on user input.
- We create a
foodItemobject using the
Foodclass’s initializer, together with the moc we are currently using. Doing so tells the moc that it is now responsible for saving information stored in the foodItem object to the database.
- To add information to the
foodItemobject we access the attributes, which we defined in the model editor earlier, in the same way we access properties of any class. This is true for all objects that are created out of
NSManagedObjectsubclasses. In this case, we add the current date to the added property of the foodItem object.
- To decide if the user chose fruit or vegetable, we use the tag property of the two food buttons (0 and 1). The first will set our foodItems
foodTypeproperty to “Fruit”, the second one to “Vegetable”.
- Once an object is filled with all the information you want, you can save it. We don’t need to write our own function for that, since Xcode already provided this function in
AppDelegate. So, we just use that function to save all the changes to the database.
- To display the newly created item in the UI we call the load data function, which we are going to implement next.
loadData() function is going to be responsible for updating the foddItems array with the new and most current data from the database. It is also going to trigger a table view update. Add the following function right below
viewDidLoad() to your
- We are creating a new fetch request of type Food. The fetch request is initialized by using the Food class’s fetch request function, which returns a preconfigured
NSFetchRequestobject with the entity name Food.
- We want to configure our fetch request in a way so that it delivers an array which shows all the food items in descending order, based on the date we added it to the database. Therefore, we need to create a
NSSortDescriptorobject and initialize it with the key that is the same as the attribute we want to use for the sort descriptor. The second argument of the initializer lets us state whether we want our result in ascending or descending order.
- Calling the fetch function of our moc and stating our
foodRequestas an argument, we can directly assign the fetch results to our foodItems array. The fetch function is able to throw an error, so we put the whole statement into a do-try block and we also catch the possible error.
- Finally, we need to refresh our table view by calling the
reloadData()function of the
We can almost run our app on the simulator. The only thing missing is a working table view. So, let’s fix that now.
A Working Table View
We already added an outlet for our table view earlier. For a fully functioning table view however, we need to add some more code in the
- We need to adopt the
UITableViewDataSourceprotocol, so add the following protocol to your class definition:
- Add self as the data source to our table view in the viewDidLoad function, and also call the
loadData()function. It should look like this:
- Add the remaining table view data source functions:
class ViewController: UIViewController, UITableViewDataSource
For the number of rows in section, we set the number of food items that we get from the database. The last table view data source function is a little more complex, so let’s have a more detailed look at that:
- After creating a
cellobject, we need to make sure to get the correct item from our
foodItemsarray. To get the corresponding item for the corresponding tableView cell, we use
- With a
foodItemready, we can access it’s
foodTypeproperty to populate the cell’s textField. We store the foodType inside a constant so that we can use it again later to determine the image we want to display in each cell.
- Core Data requires us to save dates as
NSDateobjects. To be able to format the stored date with a date formatter, we need to convert the date stored in the added property to a Date type. With the date formatter, we bring the date object into a prettier format and assign it to the cell’s detail text label.
- The last step is to determine the correct image for the cell’s image view. Therefore, we can use our
foodTypeconstant one more time.
Congratulations and next steps
You have now created a complete app based on the Core Data framework and you can start playing around with it in the simulator. You can download the tutorial files here:
[button size=”xlarge” link=”https://github.com/brianadvent/CoreDataAppEatMoreVegetable” color=”black”]GET TUTORIAL FILES[/button]
If you want to get an in-depth introductio and professional level knowledge on the great Core Data framework, have a look at my course which you can at a reduced price of just $30.
[button size=”xlarge” link=”https://www.udemy.com/become-an-ios-core-data-expert/?couponCode=BRIANADVENT” color=”black”]GET THIS COURSE FOR $30[/button]