SwiftData Code Review#
Quick Reference#
Issue TypeReference@Model, @Attribute, @Relationship, delete rulesreferences/model-design.md@Query, #Predicate, FetchDescriptor, #Indexreferences/queries.md@ModelActor, ModelContext, background operationsreferences/concurrency.mdVersionedSchema, MigrationStage, lightweight/customreferences/migrations.md
Hard gates (before reporting findings)#
Run in order; do not assert an issue until the gate for that issue passes.
- Scope — pass when: You have the target
.swift path(s) and confirmed SwiftData surface in scope (e.g. import SwiftData, @Model, @Query, @ModelActor, VersionedSchema, or migration types). If none apply, stop or narrow scope with one sentence.
- Reference — pass when: For each checklist area you evaluate (models, queries, concurrency, migrations), you opened the matching
references/*.md from the Quick Reference table or wrote N/A: no <area> in this review with a one-line reason.
- Evidence — pass when: Every finding uses the
[FILE:LINE] ISSUE_TITLE header (line range allowed) from the file you read; no finding without a cite.
- Report — pass when: Findings list cites first (or inline) using
[FILE:LINE] ISSUE_TITLE, then severity or checklist grouping—no uncited assertions.
Review Checklist#
- Models marked
final (subclassing crashes)
- @Relationship decorator on ONE side only (not both)
- Delete rules explicitly set (not relying on default .nullify)
- Relationships initialized to empty arrays, not default objects
- Batch operations used for bulk inserts (
append(contentsOf:))
- @Query not loading thousands of items on main thread
- External values in predicates captured in local variables
- Scalar comparisons in predicates (not object references)
- @ModelActor used for background operations
- PersistentIdentifier/DTOs used to pass data between actors
- VersionedSchema defined for each shipped version
- MigrationPlan passed to ModelContainer
When to Load References#
- Reviewing @Model or relationships -> model-design.md
- Reviewing @Query or #Predicate -> queries.md
- Reviewing @ModelActor or background work -> concurrency.md
- Reviewing schema changes or migrations -> migrations.md
Review Questions#
- Could this relationship assignment cause NULL foreign keys?
- Is @Relationship on both sides creating circular references?
- Could this @Query block the main thread with large datasets?
- Are model objects being passed between actors unsafely?
- Would schema changes require a migration plan?