Skip to content
advanced Phase 6 · Data Persistence

Core Data

Use Core Data for complex data models: entities, relationships, fetch requests, and batch operations.

1h 5m
3 problems
Topic Progress 0%

Core Data Stack

What is Core Data?

Core Data is Apple's object graph and persistence framework. It manages object lifecycles, relationships, and serialization to SQLite.

NSPersistentContainer

The container manages the entire Core Data stack:

import CoreData

let container = NSPersistentContainer(name: "MyApp")
container.loadPersistentStores { description, error in
    if let error = error {
        fatalError("Core Data failed to load: \(error.localizedDescription)")
    }
}
let context = container.viewContext

Stack Components

  • NSManagedObjectContext: In-memory scratchpad for objects
  • NSPersistentStoreCoordinator: Manages persistent stores
  • NSManagedObjectModel: Defines your data model

Background Context

For heavy operations off the main thread:

let backgroundContext = container.newBackgroundContext()
backgroundContext.perform {
    let obj = NSEntityDescription.insertNewObject(forEntityName: "Article", into: backgroundContext)
    try? backgroundContext.save()
}

SwiftUI Integration

@main
struct MyApp: App {
    let container: NSPersistentContainer
    init() {
        container = NSPersistentContainer(name: "MyApp")
        container.loadPersistentStores { _, error in
            if let error = error { fatalError("Failed: \(error)") }
        }
    }
    var body: some Scene {
        WindowGroup { ContentView() }
            .environment(\.managedObjectContext, container.viewContext)
    }
}

Managed Objects

NSManagedObject Subclasses

Generate or create typed subclasses:

@objc(Article)
public class Article: NSManagedObject {
    @NSManaged public var id: UUID
    @NSManaged public var title: String
    @NSManaged public var content: String
    @NSManaged public var publishedAt: Date
    @NSManaged public var author: Author?
}

extension Article {
    @nonobjc public class func fetchRequest() -> NSFetchRequest<Article> {
        return NSFetchRequest<Article>(entityName: "Article")
    }
}

Creating and Saving

let article = Article(context: context)
article.id = UUID()
article.title = "Hello World"
article.publishedAt = Date()
try? context.save()

Relationships

@objc(Author)
public class Author: NSManagedObject {
    @NSManaged public var name: String
    @NSManaged public var articles: NSSet?
}

// Access
if let articles = author.articles?.allObjects as? [Article] {
    for article in articles { print(article.title) }
}

// Set
author.addToArticles(article)

Fetch Requests

Basic Fetch

let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Article")
let articles = try context.fetch(request) as? [Article] ?? []

Predicates

request.predicate = NSPredicate(format: "isPublished == %@", NSNumber(value: true))
request.predicate = NSPredicate(format: "title CONTAINS[cd] %@", searchText)
request.predicate = NSPredicate(format: "publishedAt > %@", lastWeek as NSDate)

let compound = NSCompoundPredicate(andPredicateWithSubpredicates: [
    NSPredicate(format: "isPublished == %@", true),
    NSPredicate(format: "title CONTAINS %@", searchText)
])
request.predicate = compound

Sorting and Limits

request.sortDescriptors = [
    NSSortDescriptor(key: "publishedAt", ascending: false),
    NSSortDescriptor(key: "title", ascending: true)
]
request.fetchLimit = 20
request.fetchOffset = 0
request.fetchBatchSize = 20

Batch Operations

Delete multiple objects efficiently:

let batchDelete = NSBatchDeleteRequest(fetchRequest: Article.fetchRequest())
try? context.execute(batchDelete)

// Batch update
let batchUpdate = NSBatchUpdateRequest(entityName: "Article")
batchUpdate.predicate = NSPredicate(format: "isPublished == %@", false)
batchUpdate.propertiesToUpdate = ["isPublished": true]
try? context.execute(batchUpdate)

Async Fetch

let fetchRequest = Article.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "isPublished == %@", true)

let articles = try await context.perform {
    try self.context.fetch(fetchRequest)
}

Quiz

1. What is NSPersistentContainer?

Question 1 options

2. What property wrapper defines Core Data attributes?

Question 2 options

3. What is NSBatchDeleteRequest used for?

Question 3 options

4. How do you perform Core Data operations off the main thread?

Question 4 options

Flashcards

Question

What is the Core Data stack?

Answer

Three components: NSManagedObjectContext (scratchpad), NSPersistentStoreCoordinator (store manager), NSManagedObjectModel (schema).

Question

How do you create a background context?

Answer

Use container.newBackgroundContext() and perform operations within perform {} block.

Question

What is NSFetchRequest?

Answer

A request object used to fetch data from Core Data with predicates, sort descriptors, and limits.

Question

How do you batch delete in Core Data?

Answer

Use NSBatchDeleteRequest with a fetch request to delete objects at the store level.

Revision Notes

Key Takeaways

  • 1. NSPersistentContainer manages the entire Core Data stack
  • 2. @NSManaged marks Core Data-managed properties
  • 3. Use background contexts for heavy operations to avoid blocking the UI
  • 4. NSBatchDeleteRequest and NSBatchUpdateRequest handle bulk operations efficiently
  • 5. NSFetchRequest with predicates provides flexible data querying

Interview Tips

  • Explain the Core Data stack components and their roles
  • Know the difference between viewContext and background contexts
  • Describe when to use batch operations vs individual deletes
  • Discuss Core Data vs SwiftData trade-offs

Cheat Sheet

NSPersistentContainer: Encapsulates Core Data stack. NSManagedObjectContext: Object scratchpad. @NSManaged: Core Data properties. NSFetchRequest with predicates and sort descriptors. NSBatchDeleteRequest for bulk deletes. Background contexts for off-main-thread work.