Getting Started with Core Data Tutorial

Learn the basics of building the data layer of your iOS app in this getting started with Core Data tutorial! By Pietro Rea.

4.6 (62) · 3 Reviews

Download materials
Save for later

This is an abridged chapter from our book Core Data by Tutorials, which has been completely updated for Swift 4.2 and iOS 12. This tutorial is presented as part of our iOS 12 Launch Party — enjoy!

Welcome to Core Data!

In this tutorial, you’ll write your very first Core Data app. You’ll see how easy it is to get started with all the resources provided in Xcode, from starter code templates to the Data Model editor.

You’re going to hit the ground running right from the start. By the end of the tutorial you’ll know how to:

  • Model data using Xcode’s model editor
  • Add new records to Core Data
  • Fetch a set of records from Core Data
  • Display the fetched records using a table view.

You’ll also get a sense of what Core Data is doing behind the scenes, and how you can interact with the various moving pieces.

Getting Started

Open Xcode and create a new iOS project based on the Single View App template. Name the app HitList and make sure Use Core Data is checked.

Checking the Use Core Data box will cause Xcode to generate boilerplate code for what’s known as an NSPersistentContainer in AppDelegate.swift.

The NSPersistentContainer consists of a set of objects that facilitate saving and retrieving information from Core Data. Inside this container is an object to manage the Core Data state as a whole, an object representing the Data Model, and so on.

The standard stack works well for most apps, but depending on your your app and its data requirements, you can customize the stack to be more efficient.

Note: Not all Xcode templates under iOS ▸ Application have the option to start with Core Data. In Xcode 10, only the Master-Detail App and Single View App templates have the Use Core Data checkbox.

The idea for this sample app is simple: There will be a table view with a list of names for your very own “hit list”. You’ll be able to add names to this list, and eventually, use Core Data to make sure the data is stored between sessions. We don’t condone violence on this site, so you can think of this app as a favorites list to keep track of your friends too, of course!

Click on Main.storyboard to open it in Interface Builder. Select the view controller on the canvas and embed it inside a navigation controller. From Xcode’s Editor menu, select Embed In… ▸ Navigation Controller.

Click on the navigation controller’s navigation bar to select it, then click on Prefers Large Titles in the Attributes Inspector. This will give the sample app a title style that matches Apple’s stock apps.

Next, drag a Table View from the object library into the view controller, then resize it so it covers the entire view.

If not already open, use the icon located in the lower left corner of your canvas to open Interface Builder’s document outline.

Ctrl-drag from the Table View in the document outline to its parent view and select the Leading Space to Safe Area constraint:

Do this three more times, selecting the constraints Trailing Space to Safe Area, Top Space to Safe Area and finally, Bottom Space to Safe Area. Adding those four constraints will make the table view fill its parent view.

Next, drag a Bar Button Item and place it on the view controller’s navigation bar. Finally, select the bar button item and change its system item to Add.

Your canvas should look similar to the following screenshot:

Every time you tap the Add button, an alert controller containing a text field will appear. From there, you’ll be able to type someone’s name into the text field. Tapping Save will save the name, dismiss the alert controller and refresh the table view, displaying all the names you’ve entered.

But first, you need to make the view controller the table view’s data source. In the canvas, Ctrl-drag from the table view to the yellow view controller icon above the navigation bar, as shown below, and click on dataSource:

In case you’re wondering, you don’t need to set up the table view’s delegate since tapping on the cells won’t trigger any action. It doesn’t get simpler than this!

Open the assistant editor by pressing Command-Option-Enter or by selecting the middle button on the Editor toolset on the Xcode bar.

Ctrl-drag from the table view onto ViewController.swift inside the class definition to create an IBOutlet.

Next, name the new IBOutlet property tableView, resulting in the following line:

@IBOutlet weak var tableView: UITableView!

Next, Ctrl-drag from the Add button into ViewController.swift just below your viewDidLoad() definition. This time, create an action instead of an outlet, naming the method addName, with a type UIBarButtonItem:

@IBAction func addName(_ sender: UIBarButtonItem) {

You can now refer to the table view and the bar button item’s action in code.

Next, you’ll set up the model for the table view. Add the following property to ViewController.swift below the tableView IBOutlet:

var names: [String] = []

names is a mutable array holding string values displayed by the table view. Next, replace the implementation of viewDidLoad() with the following:

override func viewDidLoad() {
  title = "The List"
                     forCellReuseIdentifier: "Cell")

This will set a title on the navigation bar and register the UITableViewCell class with the table view.

Note: register(_:forCellReuseIdentifier:) guarantees your table view will return a cell of the correct type when the Cell reuseIdentifier is provided to the dequeue method.

Next, still in ViewController.swift, add the following UITableViewDataSource extension below your class definition for ViewController:

// MARK: - UITableViewDataSource
extension ViewController: UITableViewDataSource {
  func tableView(_ tableView: UITableView,
                 numberOfRowsInSection section: Int) -> Int {
    return names.count
  func tableView(_ tableView: UITableView,
                 cellForRowAt indexPath: IndexPath)
                 -> UITableViewCell {

    let cell =
      tableView.dequeueReusableCell(withIdentifier: "Cell",
                                    for: indexPath)
    cell.textLabel?.text = names[indexPath.row]
    return cell

If you’ve ever worked with UITableView, this code should look very familiar. First you return the number of rows in the table as the number of items in your names array.

Next, tableView(_:cellForRowAt:) dequeues table view cells and populates them with the corresponding string from the names array.

Next, you need a way to add new names so the table view can display them. Implement the addName IBAction method you Ctrl-dragged into your code earlier:

// Implement the addName IBAction
@IBAction func addName(_ sender: UIBarButtonItem) {
  let alert = UIAlertController(title: "New Name",
                                message: "Add a new name",
                                preferredStyle: .alert)
  let saveAction = UIAlertAction(title: "Save",
                                 style: .default) {
    [unowned self] action in
    guard let textField = alert.textFields?.first,
      let nameToSave = textField.text else {
  let cancelAction = UIAlertAction(title: "Cancel",
                                   style: .cancel)
  present(alert, animated: true)

Every time you tap the Add button, this method will present a UIAlertController with a text field and two buttons: Save and Cancel.

Save inserts the text fields current text into the names array then reloads the table view. Since the names array is the model backing the table view, whatever you type into the text field will appear in the table view.

Finally, build and run your app for the first time. Next, tap the Add button. The alert controller will look like this:

Add four or five names to the list. You should see something similar to below:

Your table view will display the data and your array will store the names, but the big thing missing here is persistence. The array is in memory but if you force quit the app or reboot your device, your hit list will be wiped out. Core Data provides persistence, meaning it can store data in a more durable state so it can outlive an app re-launch or a device reboot.

You haven’t added any Core Data elements yet, so nothing should persist after you navigate away from the app. Let’s test this out. Press the Home button if you’re using a physical device or the equivalent (Shift + ⌘ + H) if you’re using the Simulator. This will take you back to the familiar app grid on the home screen:

From the home screen, tap the HitList icon to bring the app back to the foreground. The names are still on the screen. What happened?

When you tap the Home button, the app currently in the foreground goes to the background. When this happens, the operating system flash-freezes everything currently in memory, including the strings in the names array. Similarly, when it’s time to wake up and return to the foreground, the operating system restores what used to be in memory as if you’d never left.

Apple introduced these advances in multitasking back in iOS 4. They create a seamless experience for iOS users but add a wrinkle to the definition of persistence for iOS developers. Are the names really persisted?

No, not really. If you had completely killed the app in the fast app switcher or turned off your phone, those names would be gone. You can verify this as well. With the app in the foreground, enter the fast app switcher. You can do this by either double tapping the Home button if your device has one or slowly dragging upwards from the bottom of the screen if you’re on an iPhone X.

From here, flick the HitList app snapshot upwards to terminate the app. If you’re working on an iPhone X, you have to long-press the app snapshot until a red delete button appears on the top right.

After you remove the app from the app switcher, there should be no trace of HitList in living memory (no pun intended). Verify the names are gone by returning to the home screen and tapping on the HitList icon to trigger a fresh launch.

The difference between flash-freezing and persistence may be obvious if you’ve worked with iOS for some time and are familiar with the way multitasking works. In a user’s mind, however, there is no difference. The user doesn’t care why the names are still there, whether the app went into the background and came back, or because the app saved and reloaded them. All that matters is the names are still there when the app comes back!

So the real test of persistence is whether your data is still there after a fresh app launch.