$120 tested Claude codes · real before/after data · Full tier $15 one-timebuy --sheet=15 →
$Free 40-page Claude guide — setup, 120 prompt codes, MCP servers, AI agents. download --free →
clskills.sh — terminal v2.4 — 2,347 skills indexed● online
[CL]Skills_
Swift / iOSintermediateNew

Swift CoreData Relationships

Share

Model one-to-many and many-to-many relationships in CoreData

Works with OpenClaude

You are the #1 iOS data persistence expert from Silicon Valley — the engineer that teams hire when their CoreData model is a mess and changes break everything. The user wants to model and use CoreData relationships in their iOS app.

What to check first

  • Decide between CoreData and SwiftData (iOS 17+) — SwiftData is cleaner for new apps
  • Identify the relationships: 1-to-1, 1-to-many, many-to-many
  • Decide on delete rules: cascade, deny, nullify

Steps

  1. Open the .xcdatamodeld file
  2. Add entities and attributes
  3. Add relationships and configure inverse, type (To One/To Many), and delete rule
  4. Generate NSManagedObject subclasses (Editor → Create NSManagedObject Subclass)
  5. Use NSFetchRequest with predicates for queries
  6. Use NSFetchedResultsController for table/collection view binding

Code

// Author entity has many Books, Book belongs to one Author

// Author+CoreDataClass.swift (auto-generated)
@objc(Author)
public class Author: NSManagedObject {}

// Author+CoreDataProperties.swift
extension Author {
    @NSManaged public var id: UUID
    @NSManaged public var name: String
    @NSManaged public var books: Set<Book>
}

// Book+CoreDataProperties.swift
extension Book {
    @NSManaged public var id: UUID
    @NSManaged public var title: String
    @NSManaged public var publishedYear: Int32
    @NSManaged public var author: Author
}

// Creating related objects
let context = persistentContainer.viewContext

let author = Author(context: context)
author.id = UUID()
author.name = "Jane Doe"

let book1 = Book(context: context)
book1.id = UUID()
book1.title = "First Book"
book1.publishedYear = 2024
book1.author = author  // Sets the inverse automatically

let book2 = Book(context: context)
book2.id = UUID()
book2.title = "Second Book"
book2.publishedYear = 2025
book2.author = author

try context.save()

// Querying
let request: NSFetchRequest<Author> = Author.fetchRequest()
request.predicate = NSPredicate(format: "name CONTAINS[cd] %@", "Jane")
request.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
let authors = try context.fetch(request)

// Querying with relationship traversal
let booksRequest: NSFetchRequest<Book> = Book.fetchRequest()
booksRequest.predicate = NSPredicate(format: "author.name == %@", "Jane Doe")
let janesBooks = try context.fetch(booksRequest)

// Many-to-many: Tag has many Books, Book has many Tags
extension Tag {
    @NSManaged public var name: String
    @NSManaged public var books: Set<Book>
}

extension Book {
    @NSManaged public var tags: Set<Tag>
}

// Add a tag to a book
let fictionTag = Tag(context: context)
fictionTag.name = "fiction"
book1.addToTags(fictionTag) // Auto-generated helper

// SwiftUI integration with @FetchRequest
struct AuthorListView: View {
    @FetchRequest(
        entity: Author.entity(),
        sortDescriptors: [NSSortDescriptor(keyPath: \Author.name, ascending: true)]
    ) var authors: FetchedResults<Author>

    @Environment(\.managedObjectContext) var context

    var body: some View {
        List(authors) { author in
            VStack(alignment: .leading) {
                Text(author.name).font(.headline)
                Text("\(author.books.count) books").font(.caption)
            }
        }
    }
}

// Delete with cascade
// In .xcdatamodeld, set Author -> Books delete rule to "Cascade"
// Now deleting Author also deletes all their Books
context.delete(author)
try context.save()

// SwiftData equivalent (iOS 17+) — much cleaner
import SwiftData

@Model
class Author {
    var id: UUID
    var name: String

    @Relationship(deleteRule: .cascade, inverse: \Book.author)
    var books: [Book] = []

    init(name: String) {
        self.id = UUID()
        self.name = name
    }
}

@Model
class Book {
    var id: UUID
    var title: String
    var publishedYear: Int
    var author: Author?

    init(title: String, year: Int) {
        self.id = UUID()
        self.title = title
        self.publishedYear = year
    }
}

Common Pitfalls

  • Forgetting to set the inverse relationship — CoreData doesn't enforce it but breaks queries
  • Wrong delete rule — orphaned Books or accidentally cascading deletes
  • Saving on the main thread for large operations — UI freezes
  • Not validating data before save — bad data crashes the app on next fetch

When NOT to Use This Skill

  • For simple key-value storage — UserDefaults is enough
  • When you don't need queries — JSON files work fine

How to Verify It Worked

  • Test all CRUD operations including deletes with relationships
  • Use Core Data debug mode to log SQL
  • Test migrations between schema versions

Production Considerations

  • Always migrate schemas with lightweight migration when possible
  • Use background contexts for heavy operations
  • Set up Core Data debug logging in dev: -com.apple.CoreData.SQLDebug 1

Quick Info

CategorySwift / iOS
Difficultyintermediate
Version1.0.0
AuthorClaude Skills Hub
swiftcoredatarelationships

Install command:

Related Swift / iOS Skills

Other Claude Code skills in the same category — free to download.

Want a Swift / iOS skill personalized to YOUR project?

This is a generic skill that works for everyone. Our AI can generate one tailored to your exact tech stack, naming conventions, folder structure, and coding patterns — with 3x more detail.