CloseHomeAboutBlogCourse
Bob I’m an iOS instructor/blogger from S.Korea.July 14 • 5 min read • Edit

Beginner Guide to Core Data in Swift

It doesn’t have to be that hard

I promised with my readers that the next article was going to be about CoreData. So, this article is written for anyone who has never used Core Data before.

Why Core Data?

Core Data is just a framework like UIKit. It is used to manage data/models. There are a couple of notable built-in features such as 1. change tracking of data, 2. undo and redo to data 3. Filtering 4. Save on to the disk. 5. Partial loading unlike UserDefaults.

It is true that there are other frameworks built by non-Apple engineers such as Realm which acts like Core Data and feel free to use that instead. I’m not going to talk about pros and cons in this article. (I also don’t know much of it)

What I think you will learn

This is a starter’s guide. I’m not going to dive in deeply. However, you will be able to save, retrieve, delete data from the disk. I assume you are aware of the meaning of delegate, optionals and how to use UITableView.

If you are not comfortable with OOP, delegate, optionals, and error handling, you might want to join Learn Swift with Bob.

UI

Every starter project begins with creating a decent UI first and, of course, a to-do app. There are two view controllers. The first is only comprised of a table and you can add tasks from the second view controller. Once you click the “Add Task” button on the second viewcontroller, it will pop back to the first view controller and you will see the item listed.

UIStoryboard

The Final Product

I’m not going to talk about how to implement the UI in Storyboard. I posted source code for you on the bottom of this article, so feel free to just read through this tutorial first and then play around with it.

Let's Get Real

When you first create a project, you have to specifically mention that you are going to use Core Data

Core Data Checked

Once you do, you will see a weird looking file name called .xcdatamodeled Don’t worry. It’s just like a spreadsheet file. Click on it, and you will see Entities and Attributes

Entities and Attributes

I’ve added Task under Entities and name under Attributes. Imagine, Entities are like an array of humans and attributes are legs, hands, fingers, and so on.

So, let’s start off with saving data on the second viewcontroller which I call it as AddTaskViewController.

Of course, in order to save, we must have the access to the core data stack. There are two scary words you have to remember: NSPersistentContainer and NSManagedObjectContext The relationship is rather straight forward. The container is like a box that contains the core data stack and context is like a hole in the box that allows users to save/fetch data from the box.

By the way, if you click on AppDelegate.swift, you will see Core Data related methods and properties pre-defined when you first create your project. So, all we have to do is to use those methods and properties. I know it sounds a bit rough.

So, the code below is to show you how to access the NSManagedObjectContext located in the AppDelegate.swift file and use the built-in saveContext function to save data when a user writes something in the textfield and then clicks the button.

class AddTaskViewController: UIViewController {
  @IBOutlet weak var taskTextField: UITextField!
  override func viewDidLoad() {
    super.viewDidLoad()
  }
  @IBAction func buttonTapped(_ sender: UIButton) {
    let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
    let task = Task(context: context) // Link Task & Context
    task.name = taskTextField.text!

    // Save the data to coredata
    (UIApplication.shared.delegate as! AppDelegate).saveContext()

    let _ = navigationController?.popViewController(animated: true)
  }

` ``

Since `Task` has been linked to `context`, the `saveContext` function is used to tell context to store its name. By the way, this is how `saveContext` looks like in `AppDelegate.swift` (No need to memorize but useful to take a look)

swift func saveContext () { let context = persistentContainer.viewContext if context.hasChanges {

do {
  try context.save()
  } catch {
    let nserror = error as NSError
    fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
  }
}
Now, it’s time to display the name of each task you’ve stored in the disk by fetching. Before we fill up the table, take a look at the top part of the `ViewController` file.

swift class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

@IBOutlet weak var tableView: UITableView! let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext var tasks: [Task] = []

override func viewDidLoad() { super.viewDidLoad() tableView.delegate = self tableView.dataSource = self }

override func viewWillAppear(_ animated: Bool) { getData() tableView.reloadData() } ```

That’s right, how does getData() look like? Yes, this is the fetching part. We are going to fetch an array of Task and store it into the tasks variable.

func getData() {
  do {
    tasks = try context.fetch(Task.fetchRequest())
    } catch {
      print("Fetching Failed")
    }
  }

Now, we’ve finished fetching, it’s time to do something with the data by displaying it on each cell.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  let cell = UITableViewCell()
  let task = tasks[indexPath.row]

  if let myName = task.name {
    cell.textLabel?.text = myName
  }
  return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  return tasks.count
}

Quite similar? Once you’ve finished fetching, everything else is pretty much the same. But, how about deleting?

We have to delete using through the “hole”, NSManagedObjectContext, and then refetch and reload the table once again.

func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
  if editingStyle == .delete {
    let task = tasks[indexPath.row]
    context.delete(task)
    (UIApplication.shared.delegate as! AppDelegate).saveContext()

    do {
      tasks = try context.fetch(Task.fetchRequest())
      } catch {
        print("Fetching Failed")
      }
    }
    tableView.reloadData()
  }

Last Remarks

I haven’t much dived into CoreData but I hope this is a starting point for many developers out there. I’ve released an intermediate Swift course that covers enums, generics, protocols, closures, memory management, and other advanced topics. You may join me here.

Resources

Source Code

About Me

iOS Developer from South Korea. Feel free to follow my story on Instagram or get serious on LinkedIn