Skill v1.0.1
currentAutomated scan100/1002 files
version: "1.0.1" name: persistence-setup description: Generates SwiftData or CoreData persistence layer with optional iCloud sync. Use when user wants to add local storage, data persistence, or cloud sync. allowed-tools: [Read, Write, Edit, Glob, Grep, Bash, AskUserQuestion] last_verified: 2026-07-16 review_by: 2027-06-22 os_version: iOS 27 / macOS 27
Persistence Setup Generator
Generates a production-ready persistence layer using SwiftData (iOS 17+) or CoreData with optional iCloud (CloudKit) sync.
When This Skill Activates
- User asks to "add persistence" or "set up data storage"
- User mentions "SwiftData", "CoreData", or "local storage"
- User wants to "sync data to iCloud" or "enable cloud sync"
- User asks about "offline storage" or "data models"
Pre-Generation Checks (CRITICAL)
1. Project Context Detection
Before generating, ALWAYS check:
# Check deployment targetcat Package.swift | grep -i "platform"# Or check project.pbxproj# Find existing persistence implementationsrg -l "ModelContainer|NSPersistentContainer|@Model|@Entity" --type swift# Check for existing SwiftData modelsrg "@Model" --type swift | head -5# Check for CoreData stackrg "NSManagedObjectContext|NSPersistentStore" --type swift | head -5# Check existing entitlements for iCloudcat *.entitlements 2>/dev/null | grep -i "icloud"
2. Framework Selection
Use SwiftData if:
- Deployment target is iOS 17+ / macOS 14+
- User explicitly requests SwiftData
- No existing CoreData implementation
Use CoreData if:
- Deployment target < iOS 17
- Existing CoreData stack present
- User explicitly requests CoreData
3. Conflict Detection
If existing persistence found:
- Ask: Extend existing, migrate to SwiftData, or create separate?
Configuration Questions
Ask user via AskUserQuestion:
- Framework choice?
- SwiftData (iOS 17+, recommended)
- CoreData (older targets)
- Enable iCloud sync?
- Yes (requires CloudKit entitlement)
- No (local only)
- Generate example model?
- Yes (with sample Item model)
- No (just infrastructure)
Generation Process
Step 1: Create Core Files
Always generate:
Sources/Persistence/├── PersistenceController.swift # Container setup├── Repository.swift # Repository protocol└── SwiftDataRepository.swift # Concrete implementation
If example model requested:
Sources/Persistence/Models/└── Item.swift # Sample @Model
If iCloud enabled:
Sources/Persistence/CloudSync/├── CloudKitConfiguration.swift # Container identifier└── SyncStatus.swift # Sync monitoring
Step 2: Read Templates
Read templates from this skill:
templates/PersistenceController.swifttemplates/Repository.swifttemplates/SwiftDataRepository.swifttemplates/ExampleModel.swifttemplates/CloudKitConfiguration.swift(if iCloud)templates/SyncStatus.swift(if iCloud)
Step 3: Customize for Project
Adapt templates to match:
- Project naming conventions
- Existing model patterns
- Bundle identifier for CloudKit container
Step 4: Integration
Basic Integration:
@mainstruct MyApp: App {let container = PersistenceController.shared.containervar body: some Scene {WindowGroup {ContentView().modelContainer(container)}}}
With iCloud sync:
@mainstruct MyApp: App {let container = PersistenceController.shared.containervar body: some Scene {WindowGroup {ContentView().modelContainer(container).environment(\.syncStatus, SyncStatus.shared)}}}
iCloud Sync Setup
Required Capabilities (Xcode)
- iCloud capability:
- Check "CloudKit"
- Add container:
iCloud.com.yourcompany.yourapp
- Background Modes (optional, for background sync):
- Check "Remote notifications"
Required Entitlements
<key>com.apple.developer.icloud-container-identifiers</key><array><string>iCloud.com.yourcompany.yourapp</string></array><key>com.apple.developer.icloud-services</key><array><string>CloudKit</string></array>
CloudKit Dashboard Setup
- Go to CloudKit Dashboard
- Select your container
- Schema is auto-created from @Model classes
- Deploy schema to production before release
Generated Code Patterns
Repository Protocol
protocol Repository<T>: Sendable {associatedtype T: PersistentModelfunc fetch(predicate: Predicate<T>?, sortBy: [SortDescriptor<T>]) async throws -> [T]func insert(_ item: T) async throwsfunc delete(_ item: T) async throwsfunc save() async throws}
SwiftData Model
@Modelfinal class Item {var title: Stringvar timestamp: Datevar isCompleted: Boolinit(title: String, timestamp: Date = .now, isCompleted: Bool = false) {self.title = titleself.timestamp = timestampself.isCompleted = isCompleted}}
Container with CloudKit
let container = try ModelContainer(for: Item.self,configurations: ModelConfiguration(cloudKitDatabase: .private("iCloud.com.yourcompany.yourapp")))
Verification Checklist
After generation, verify:
- [ ] App launches without crashes
- [ ] Data persists between app launches
- [ ] Models compile without errors
- [ ] (If iCloud) CloudKit container exists in dashboard
- [ ] (If iCloud) Data syncs between devices
- [ ] Repository pattern allows easy testing
Common Customizations
Adding New Models
@Modelfinal class Project {var name: String@Relationship(deleteRule: .cascade) var items: [Item]init(name: String, items: [Item] = []) {self.name = nameself.items = items}}// Update containerlet container = try ModelContainer(for: Item.self, Project.self)
Custom Fetch Descriptors
let descriptor = FetchDescriptor<Item>(predicate: #Predicate { $0.isCompleted == false },sortBy: [SortDescriptor(\.timestamp, order: .reverse)])let items = try modelContext.fetch(descriptor)
Migration (SwiftData)
// SwiftData handles lightweight migrations automatically// For complex migrations, use VersionedSchemaenum ItemSchemaV1: VersionedSchema {static var versionIdentifier = Schema.Version(1, 0, 0)static var models: [any PersistentModel.Type] { [Item.self] }}
Troubleshooting
iCloud Sync Not Working
- Check entitlements match CloudKit container
- Verify CloudKit Dashboard shows your container
- Check device is signed into iCloud
- Deploy schema to production if testing on release build
Data Not Persisting
- Verify
modelContainermodifier is on root view - Check
save()is called after modifications - Look for errors in Console.app
CloudKit Quota Exceeded
- Default quota is generous (free tier: 100MB asset storage)
- Consider pruning old data
- Use
cloudKitDatabase: .automaticfor shared containers
Related Skills
networking-layer- For remote API data alongside local cachesettings-screen- Often uses @AppStorage (simpler persistence)