Swift persistence
Skill jeremieb/swift-unit-test-instructions/skills/swift-persistence
A reusable framework of Claude Code instructions for Swift, SwiftUI, and UIKit projects.
npx -y skills add jeremieb/swift-unit-test-instructions --skill swift-persistenceAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 5 stars5 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Implements a persistence layer using SwiftData or CoreData following MVVM — models, repository abstraction, and testable in-memory setup. Use when user says "add CoreData", "set up SwiftData", "persist data", "save to database", "add a data model", "create Core Data entities", or "use SwiftData models".
SKILL.md
4.9 KB, as published. Nobody here has run it
Swift Persistence
Instructions
Step 1: Choose the framework
Ask if not already specified:
SwiftData or CoreData?
| SwiftData | CoreData | |
|---|---|---|
| Min iOS | iOS 17+ | iOS 8+ |
| Syntax | @Model macro, Swift-native | NSManagedObject, Objective-C roots |
| Recommended for | New projects on iOS 17+ | Legacy projects, complex migration needs |
Then load the matching reference:
- SwiftData →
references/swiftdata.md - CoreData →
references/coredata.md
Step 2: Define the models
Ask: what entities are needed? For each entity:
- Name (singular, UpperCamelCase:
Task,UserProfile,Transaction) - Properties and their types
- Relationships to other entities (one-to-one, one-to-many, many-to-many)
- Any computed properties needed
Step 3: Generate the model layer
Models go in Core/Models/ — they are plain data types, framework-agnostic where possible.
Persistence infrastructure goes in Services/Storage/:
PersistenceController.swift— container setup, in-memory preview/test variant[Entity]Repository.swift— CRUD operations for each entity[Entity]RepositoryProtocol.swift— protocol for testability
Rule: ViewModels inject a repository protocol. They never touch ModelContext or NSManagedObjectContext directly.
Services/Storage/
├── PersistenceController.swift
├── TaskRepository.swift
└── TaskRepositoryProtocol.swift
Step 4: Generate the repository protocol
Always define a protocol first so ViewModels can be tested with a mock:
// Services/Storage/TaskRepositoryProtocol.swift
protocol TaskRepositoryProtocol {
func fetchAll() throws -> [Task]
func save(_ task: Task) throws
func delete(_ task: Task) throws
}
Step 5: Wire into the ViewModel
ViewModels receive the repository via init:
@MainActor
@Observable
final class TaskListViewModel {
private(set) var tasks: [Task] = []
private let repository: TaskRepositoryProtocol
init(repository: TaskRepositoryProtocol = TaskRepository()) {
self.repository = repository
}
func loadTasks() {
tasks = (try? repository.fetchAll()) ?? []
}
}
Step 6: Generate mock for tests
final class MockTaskRepository: TaskRepositoryProtocol {
var stubbedTasks: [Task] = []
var saveCallCount = 0
var deleteCallCount = 0
func fetchAll() throws -> [Task] { stubbedTasks }
func save(_ task: Task) throws { saveCallCount += 1 }
func delete(_ task: Task) throws { deleteCallCount += 1 }
}
Step 7: Quality checklist
-
ModelContext/NSManagedObjectContextis never used in aViewModelorView - Repository protocol exists for every entity accessed by a ViewModel
- In-memory container/store exists for tests and previews
- Background context used for heavy writes (batch imports, migrations)
- Models in
Core/Models/have no direct framework import (SwiftDataorCoreData) in the ViewModel layer - Migrations are handled explicitly — no silent schema changes
Examples
Example 1: SwiftData task app
User says: "Add SwiftData to persist tasks with title, completion status, and due date"
Actions:
- Load
references/swiftdata.md - Generate
Taskmodel with@Model - Generate
PersistenceControllerwith.inMemorypreview variant - Generate
TaskRepository+TaskRepositoryProtocol - Update
TaskListViewModelto inject repository - Generate
MockTaskRepositoryfor tests
Example 2: CoreData in existing UIKit app
User says: "I need to add CoreData to my existing UIKit project to cache user profiles"
Actions:
- Load
references/coredata.md - Generate
UserProfileNSManagedObject subclass - Generate
PersistenceControllerwith in-memory option - Generate
UserProfileRepository+ protocol - Wire into existing
ProfileViewModel
Troubleshooting
SwiftData: "Context is not available" — ModelContext is being accessed outside a SwiftData-aware environment. Ensure the ModelContainer is set up at the App level and injected via .modelContainer() modifier. Never create contexts manually in ViewModels.
CoreData: merge conflicts — You are writing on the main context from a background thread. Use performBackgroundTask or a dedicated background context. Always call context.save() on the correct thread.
Tests failing because model can't be found — The in-memory store is not configured. Use PersistenceController.preview (SwiftData) or an in-memory NSPersistentContainer in your test setup.