Skip to main content
Swift for iOS Development
CHAPTER 21 Beginner

Core Data Database Basics

Updated: May 16, 2026
7 min read

# CHAPTER 21

Core Data Database Basics

1. Introduction

If UserDefaults is a tiny filing cabinet for sticky notes, Core Data is a massive, highly optimized, multi-relational SQL database built directly into every Apple device. If you are building an offline Notes app, an Expense Tracker, or a heavy offline game, you cannot rely on the internet or small preference files. You must store thousands of objects locally. In this chapter, we will master Core Data Database Basics. We will configure a local data model, define architectural Entities, and perform the four fundamental database operations: Create, Read, Update, and Delete (CRUD).

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Understand the Core Data stack and the Data Model editor.
  • Define a Core Data Entity and its Attributes.
  • Use the @FetchRequest property wrapper to pull data directly into SwiftUI.
  • Create and save new records to the database.
  • Delete existing records from the database.

3. Setting Up Core Data

When you create a brand new Xcode project, you must explicitly check the "Use Core Data" box on the setup screen. This tells Xcode to generate a .xcdatamodeld file. This file is visual! You do not write SQL code to build your database; you use Apple's visual editor.

The Persistence Controller: Xcode also generates a Persistence.swift file. This contains the NSPersistentCloudKitContainer, which is the engine that connects your code to the actual SQLite database living on the phone's hard drive.

4. Creating an Entity (The Schema)

In SQL, you create Tables. In Core Data, you create Entities.
  1. 1. Open the .xcdatamodeld file.
  1. 2. Click "Add Entity" at the bottom. Name it Note.
  1. 3. Under "Attributes", add a new attribute named title of type String.
  1. 4. Add another attribute named timestamp of type Date.

*Xcode will automatically generate a Swift Class for Note behind the scenes. You never have to write the struct manually!*

5. Injecting the Database into the App

To use Core Data across your entire SwiftUI app, the database engine must be injected into the root @main file as an environment variable.
swift
12345678910111213
@main
struct NotesApp: App {
    // 1. Grab the engine Xcode created for us
    let persistenceController = PersistenceController.shared

    var body: some Scene {
        WindowGroup {
            ContentView()
                // 2. Inject it into the environment!
                .environment(\.managedObjectContext, persistenceController.container.viewContext)
        }
    }
}

6. Reading Data: @FetchRequest

To display data, SwiftUI has a magical property wrapper called @FetchRequest. It talks to the database, grabs the array of objects, and (just like @State) *automatically redraws the UI if the database ever changes!*
swift
1234567891011121314151617181920212223
import SwiftUI
import CoreData

struct ContentView: View {
    // 1. Access the database connection we injected earlier
    @Environment(\.managedObjectContext) private var viewContext

    // 2. The Fetch Request! Ask the database for all Notes, sorted by time.
    @FetchRequest(
        entity: Note.entity(),
        sortDescriptors: [NSSortDescriptor(keyPath: \Note.timestamp, ascending: false)]
    ) private var notes: FetchedResults<Note>

    var body: some View {
        List {
            // 3. Loop through the results exactly like a normal array!
            ForEach(notes) { note in
                // Note: Core Data strings are Optional by default! Use ??
                Text(note.title ?? "Untitled")
            }
        }
    }
}

7. Creating Data (Writing to the DB)

To save a new Note, you must interact with the viewContext (the scratchpad). You create the object, assign the data, and explicitly call .save().
swift
123456789101112131415
func addNote(text: String) {
    // 1. Create a new empty record on the scratchpad
    let newNote = Note(context: viewContext)
    
    // 2. Fill it with data
    newNote.title = text
    newNote.timestamp = Date() // Current time
    
    // 3. Push the scratchpad to the permanent hard drive!
    do {
        try viewContext.save()
    } catch {
        print("Failed to save note: \(error)")
    }
}

8. Deleting Data

Deleting is identical. You find the object, tell the context to delete it, and save the changes.
swift
12345678910111213141516
// Triggered by a Swipe-to-Delete on the List
func deleteNotes(offsets: IndexSet) {
    // Find the exact notes the user swiped on
    for index in offsets {
        let noteToDelete = notes[index]
        // Tell the scratchpad to delete it
        viewContext.delete(noteToDelete)
    }
    
    // Save the changes to the hard drive!
    do {
        try viewContext.save()
    } catch {
        print("Failed to delete note: \(error)")
    }
}

9. Common Mistakes

  • Forgetting to Save: You can create 100 Note(context: viewContext) objects. They will even show up in the UI immediately because @FetchRequest monitors the scratchpad! But if you force-close the app without calling try viewContext.save(), all 100 notes will be permanently erased. You MUST commit the scratchpad to the hard drive!

10. Best Practices

  • SwiftData (The Future): In iOS 17 (2023), Apple introduced SwiftData, which is a modern, pure-Swift wrapper around Core Data. It replaces the visual .xcdatamodeld editor with simple @Model macros in code. While Core Data remains the absolute industry standard for legacy apps, SwiftData is the future of Apple persistence.

11. Exercises

  1. 1. In a visual .xcdatamodeld file, create an Entity named Task with a title (String) and isDone (Boolean).
  1. 2. Write the @FetchRequest code to retrieve all Task entities.

12. Coding Challenges

Challenge: Build the UI for the Notes app. Create a VStack. The top should be an HStack with a TextField (bound to a local @State variable) and an "Add" button that calls the addNote function. The bottom should be the List displaying the @FetchRequest data.

13. MCQ Quiz with Answers

Question 1

When building a SwiftUI application, what specific property wrapper is utilized to execute a database query against Core Data and automatically keep the UI perfectly synchronized with the results?

Question 2

In Core Data architecture, what is the role of the managedObjectContext (often referred to as the "scratchpad")?

14. Interview Questions

  • Q: Contrast the specific use cases of UserDefaults versus Core Data. Why would attempting to use UserDefaults to store 5,000 complex, relational user objects be considered catastrophic architecture?
  • Q: Explain the mechanical flow of creating and persisting a new Entity record using the NSManagedObjectContext. Why is the explicit .save() operation mandatory?
  • Q: Describe how SwiftUI's @FetchRequest property wrapper integrates seamlessly with Core Data. What advantage does it provide over manual data fetching?

15. FAQs

Q: Can I look at the actual database file on my computer to see the data? A: Yes! When running the Simulator, the app data is stored in your Mac's hidden Library folder. You can use free third-party tools like "SimPholders" or "DB Browser for SQLite" to open the raw SQL file and inspect the rows directly!

16. Summary

In Chapter 21, we architected a robust, offline-first application by mastering Core Data. We utilized Apple's visual data modeler to define relational schemas (Entities and Attributes), eliminating the need for raw SQL queries. We seamlessly bridged the database to our declarative UI utilizing the @FetchRequest property wrapper, enabling reactive, real-time data rendering. Finally, we executed full CRUD operations by manipulating the Managed Object Context (the scratchpad) and committing those changes permanently to the device's physical storage.

17. Next Chapter Recommendation

Our data is safe, but it is entirely local. If the user drops their phone in the ocean, their notes are gone forever. We need to sync data to the cloud. Proceed to Chapter 22: Firebase Integration in iOS Apps.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·