DEV Community

Avelyn Hyunjeong Choi
Avelyn Hyunjeong Choi

Posted on • Updated on

Coding with Core Data in Xcode

When do we need local device storage in iOS?

  • for cache
  • when you are not connected to the internet, you still have local data available in your app

Local Data Persistence

  • this data will be available whenever you open it
  • provided by the CoreData framework

  • SQLite relational database will be used

  • we won't be writing sql directly

  • we will be using library

What is relational database?

ERD

  • Entity Relational Diagram
  • relationship
  • entities: tables
  • attributes: table columns

entity

entity

  • core data will take care of database, table...
  • all you need to do is to define entity, class and attributes for the entity
  • instance of an entity(class): represent a row in the table
  • map relationship between core data class and sqlite classes

Steps to use Core Data framework

  1. define the entities
  2. specify the attributes
  3. describe relationships between the entities
  4. insert data

Core data

  • not a database
  • act as an interface between SQLite database and your app!

1.managed object context - interact with app
2.persistent container - interact with database tables

How to use SQLite database in xCode?
1.create a project and check "Use Core Data"
1

below file will be generated
1-1

2.click on core data file (w10c1_CoreDataApp) and + Add Entity
2

double-click Entity and rename it to Employee
2-1

2-2

3.add attributes to the Employee entity
3

make sure you check Manual/None for Codegen (Entity > Inspector > Class > Codegen)
3-1

why Manual/None?

  • core data will automatically generate a class for you in memory which you will be not seeing physically
  • if you want to make sure class exists, do not let core data generate the class for you
  • manual/none -> you will have controls over the class
  • set to class definition -> core data will also generate the class as well (hard to find bugs since you don't see the class)

4.select Editor > Create NSManagedObject Subclass, which generates a swift class representing your Entity
4

4-1

4-2

result - you should get two new files
result

5.need a reference to Core Data's managed context variable for CRUD operations

class ViewController: UIViewController {

  let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext

  override func viewDidLoad() {
    super.viewDidLoad()
  }
}
Enter fullscreen mode Exit fullscreen mode

6.CRUD operations

Create

    override func viewDidLoad() {
        super.viewDidLoad()

        addEmployee(name: "John", age: 30, department: "Frontend")
    }

  func addEmployee(name: String, age: Int, department: String) {
    // 1. Create an employee object
    let emp = Employee(context: context)

    // 2. Set the properties of that object
    emp.name = name
    emp.age = Int16(age)
    emp.department = department

    // 3. Use the context variable to save the Employee to the database table
    do {
      try context.save()
      print("Employee saved!")
    } catch {
      print("Saved failed.")
    }
  }
Enter fullscreen mode Exit fullscreen mode

How to locate the Core Data SQLite file?
1.Install this software in your Mac: https://sqlitebrowser.org/

2.add path code to AppDelegate.swift > didFinishLaunchingWithOptions

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

  let path = FileManager
    .default
    .urls(for: .applicationSupportDirectory, in: .userDomainMask)
    .last?
    .absoluteString
    .replacingOccurrences(of: "file://", with: "")
    .removingPercentEncoding
  print("Core Data DB Path :: \(path ?? "Not found")")

  return true
}
Enter fullscreen mode Exit fullscreen mode

3.run the app and get the path from the terminal

Core Data DB Path :: /Users/<USER>/Library/Developer/CoreSimulator/Devices/DA892F2C-3C83-4ED4-B5A2-D6D80257BDFC/data/Containers/Data/Application/4DE2AF5B-B77B-412F-B74D-AC3BAA023A8D/Library/Application Support/
Enter fullscreen mode Exit fullscreen mode

4.open Finder > Go > Go to Folder and copy and paste the path into window
Image description

5.open .sqlite file in DB Browser
Image description

Read

override func viewDidLoad() {
    super.viewDidLoad()

    fetchAllEmployees()
    fetchAllEmployees(age: 30)
  }

func fetchAllEmployees() {
    let fetchRequest: NSFetchRequest<Employee> = Employee.fetchRequest()

    do {
      let employees = try context.fetch(fetchRequest)

      for emp in employees {
        print(emp.name ?? "")
        print(emp.age)
        print(emp.department ?? "")
        print("-----------")
      }
    } catch {
      print("Failed to fetch employees")
    }
  }

func fetchAllEmployees(age: Int) {
    let fetchRequest: NSFetchRequest<Employee> = Employee.fetchRequest()
    fetchRequest.predicate = NSPredicate(format:"age <= %@", "\(age)")

    do {
      let employees = try context.fetch(fetchRequest)

      for emp in employees {
        print(emp.name ?? "")
        print(emp.age)
        print(emp.department ?? "")
        print("-----------")
      }
    } catch {
      print("Failed to fetch employees")
    }
  }
Enter fullscreen mode Exit fullscreen mode

Update

override func viewDidLoad() {
    super.viewDidLoad()

    updateEmployee()
  }

  func updateEmployee() {
    let fetchRequest: NSFetchRequest<Employee> = Employee.fetchRequest()

    do {
      let employees = try context.fetch(fetchRequest)

      let firstEmp = employees.first
      firstEmp?.age = 30

      try context.save()
      print("Employee updated")
    } catch {
      print("Failed to update employee")
    }
  }
Enter fullscreen mode Exit fullscreen mode

Delete

let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext

  override func viewDidLoad() {
    super.viewDidLoad()

    deleteEmployee()
  }

  func deleteEmployee() {
    let fetchRequest: NSFetchRequest<Employee> = Employee.fetchRequest()

    do {
      let employees = try context.fetch(fetchRequest)

      if let lastEmp = employees.last {
        context.delete(lastEmp)
      }

      try context.save()
      print("Employee deleted")
    } catch {
      print("Failed to delete employee")
    }
  }
Enter fullscreen mode Exit fullscreen mode

Top comments (0)