smithery.ai

swiftdata-persistence

SwiftData persistence patterns for iOS apps with @Model and SwiftData containers

First seen Apr 13, 2026

Installation

$ npx skills add https://smithery.ai

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery.ai · top by installs.

npx skills add https://smithery.ai

Browse all from smithery.ai

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 4,284 B
  • docs SUMMARY.md 109 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 1 installs

SKILL.md

SwiftData Persistence Skill

Overview

SwiftData persistence patterns for iOS apps, enabling durable local storage that survives app restarts.

SwiftData Models

Persisted Cart Item

@Model
final class PersistedCartItem {
    @Attribute(.unique) var sku: String
    var qty: Int
    var cart: PersistedCart?
    
    init(sku: String, qty: Int) {
        self.sku = sku
        self.qty = qty
    }
}

Persisted Cart

@Model
final class PersistedCart {
    @Attribute(.unique) var ownerId: String
    var version: Int
    @Relationship(deleteRule: .cascade, inverse: \PersistedCartItem.cart)
    var items: [PersistedCartItem]
    
    init(ownerId: String, version: Int = 0) {
        self.ownerId = ownerId
        self.version = version
        self.items = []
    }
}

Persisted Outbox Operation

@Model
final class PersistedCartOp {
    @Attribute(.unique) var opId: UUID  // Survives app restart
    var ownerIdData: Data               // Encoded CartOwner
    var typeData: Data                  // Encoded CartOpType
    var attempts: Int
    var nextRetryAt: Date
    
    init(op: CartOp) throws {
        self.opId = op.id
        self.ownerIdData = try JSONEncoder().encode(op.owner)
        self.typeData = try JSONEncoder().encode(op.type)
        self.attempts = op.attempts
        self.nextRetryAt = op.nextRetryAt
    }
}

Model Container Setup

@main
struct App: App {
    let container: ModelContainer
    
    init() {
        let schema = Schema([
            PersistedCart.self,
            PersistedCartItem.self,
            PersistedCartOp.self
        ])
        
        let configuration = ModelConfiguration(
            "ECommerceStore",
            schema: schema,
            isStoredInMemoryOnly: false
        )
        
        container = try! ModelContainer(
            for: schema,
            configurations: [configuration]
        )
    }
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .modelContainer(container)
    }
}

Persistent Store Implementation

public actor PersistentCartStore: CartStoreProtocol {
    private let container: ModelContainer
    
    public init(container: ModelContainer) {
        self.container = container
    }
    
    public func get(owner: CartOwner) async -> Cart {
        let context = ModelContext(container)
        let ownerId = owner.id
        
        let descriptor = FetchDescriptor<PersistedCart>(
            predicate: #Predicate { $0.ownerId == ownerId }
        )
        
        guard let persisted = try? context.fetch(descriptor).first else {
            return Cart.empty(owner: owner)
        }
        
        return Cart(
            owner: owner,
            items: persisted.items.map { CartItem(sku: $0.sku, qty: $0.qty) },
            version: persisted.version
        )
    }
    
    public func upsert(_ cart: Cart) async {
        let context = ModelContext(container)
        let ownerId = cart.owner.id
        
        // Delete existing
        try? context.delete(model: PersistedCart.self, where: #Predicate {
            $0.ownerId == ownerId
        })
        
        // Insert new
        let persisted = PersistedCart(ownerId: ownerId, version: cart.version)
        persisted.items = cart.items.map {
            PersistedCartItem(sku: $0.sku, qty: $0.qty)
        }
        context.insert(persisted)
        
        try? context.save()
    }
}

Swappable Architecture

// In-memory for development/testing
let cartStore = CartStore()

// SwiftData for production
let cartStore = PersistentCartStore(container: .shared)

// Both conform to CartStoreProtocol - Repository doesn't know the difference
let repository = CartRepository(store: cartStore, ...)

Key Patterns

Pattern Implementation
Protocol abstraction CartStoreProtocol
Actor isolation @ModelActor or manual context
Unique constraints @Attribute(.unique)
Cascade delete @Relationship(deleteRule: .cascade)
Swappable stores Protocol + DI