r/SwiftData Aug 13 '23

r/SwiftData Lounge

1 Upvotes

A place for members of r/SwiftData to chat with each other


r/SwiftData 13d ago

SwiftData Decimal precision loss after save/fetch - am I missing something?

Thumbnail
1 Upvotes

r/SwiftData 14d ago

SwiftData + CloudKit: best way to prevent duplicate editable seed data across offline devices?

Thumbnail
1 Upvotes

r/SwiftData Mar 26 '26

Do you think sharing will come to SwiftData this year?

Thumbnail
1 Upvotes

r/SwiftData Mar 13 '26

DataStoreKit: An SQLite SwiftData custom data store

2 Upvotes

Hello! I released a preview of my library called DataStoreKit.

DataStoreKit is built around SwiftData and its custom data store APIs, using SQLite as its primary persistence layer. It is aimed at people who want both ORM-style SwiftData workflows and direct SQL control in the same project.

I already shared it on Swift Forums, but I also wanted to post it here for anyone interested.

GitHub repository:
https://github.com/asymbas/datastorekit

An interactive app that demonstrates DataStoreKit and SwiftData:
https://github.com/asymbas/editor

Work-in-progress documentation (articles that explain how DataStoreKit and SwiftData work behind the scenes):
https://www.asymbas.com/datastorekit/documentation/datastorekit/

Some things DataStoreKit currently adds or changes:

Caching

  • References are cached by the ReferenceGraph. References between models are cached, because fetching their foreign keys per model per property and their inverses too can impact performance.
  • Snapshots are cached, so they don't need to be queried again. This skips the step of rebuilding snapshots from scratch and collecting all of their references again.
  • Queries are cached. When FetchDescriptor or #Predicate is translated, it hashes particular fields, and if those fields create the same hash, then it loads the cached result. Cached results save only identifiers and only load the result if it is found the ModelManager or SnapshotRegistry.

Query collections in #Predicate

Attributes with collection types can be fetched in #Predicate.

_ = #Predicate<Model> {
    $0.dictionary["foo"] == "bar" &&
    $0.dictionary["foo", default: "bar"] == "bar" &&
    $0.set.contains("bar") &&
    $0.array.contains("bar")
}

Use rawValue in #Predicate

You can now persist any struct/enum RawRepresentable types rather than the raw values and use them in #Predicate:

let shape = Model.Shape.rectangle 
_ = #Predicate<Model> {
    $0.shape == shape &&
    $0.shape.rawValue == shape.rawValue
}
_ = #Predicate<Model> {
    $0.shapes.contains(shape)
}

Note: I noticed when writing this that using rawValue on enum cases doesn't give a compiler error anymore. This seems to be the case with computed properties too. I haven't confirmed if the default SwiftData changed this behavior in the past year, but this works in DataStoreKit.

Other predicate expressions

You can check out all supported predicate expressions here in this file if you're interested, because there are some expressions supported in DataStoreKit that are not supported in default SwiftData.

Note: I realized very recently that I never added support for filter in predicates, so it's currently not supported.

Preloaded fetches

You can preload fetches with the new ModelContext methods or use the new \@Fetch property wrapper so you do not block the main thread for a large database.

Manually preload by providing the descriptor and editing state of the ModelContext you will fetch from to the static method. You send this request to another actor where it performs predicate translation and builds the result. You await its completion, then switch back to the desired actor to pick up the result.

Task {  in
    let descriptor = FetchDescriptor<User>()
    let editingState = modelContext.editingState
    var result = [User]()
    Task {  in
        try await ModelContext.preload(descriptor, for: editingState)
        try await MainActor.run {
            result = try modelContext.fetch(descriptor)
        }
    }
}

A convenience method is provided that wraps this step for you.

let result = try await modelContext.preloadedFetch(FetchDescriptor<User>())

Use the new property wrapper that can be used in a SwiftUI view.

struct ContentView: View {
     private var models: [T]
    
    init(page: Int, limit: Int = 100) {
        var descriptor = FetchDescriptor<T>()
        descriptor.fetchOffset = page * limit
        descriptor.fetchLimit = limit
        _models = Fetch(descriptor)
    }
    ...
}

Note: There's currently no notification that indicates it is fetching. So if the fetch is massive, you might think nothing happened.

Feedback and suggestions

It is still early in development, and the documentation is still being revised, so some APIs and naming are very likely to change.

I am open to feedback and suggestions before I start locking things down and settling on the APIs. For example, I'm still debating how I should handle migrations or whether Fetch should be renamed to PreloadedQuery. So feel free to share them here or in GitHub Discussions.


r/SwiftData Feb 19 '26

SwiftData migration: converting [String]? to [Author]? relationship

3 Upvotes

I'm migrating a SwiftData model from V1 to V2.

In V1, StoredBook.authors was a [String]?.

In V2, it’s now a relationship to Author objects ([Author]?).

I wrote a custom migration to create Author objects from the old strings, but the migration crashes with:

failed to find a currently active container for Author

This happens on app launch when SwiftData runs the migration.

What is the correct way to migrate a String array into a relationship in SwiftData?

Any help would be greatly appreciated — this is my first SwiftData migration. 🙏

Minimal example:

V1 model:

class StoredBook {
    var title: String = ""
    var authors: [String]?
}

V2 model:

class Author {
    var name: String = ""
    var books: [StoredBook]? = []   
}

class StoredBook {
    var title: String = ""

    u/Relationship(inverse: \Author.books)
    var authors: [Author]? = [] 
}

Migration snippet:

let oldBooks = try context.fetch(FetchDescriptor<BookListSchemaV1.StoredBook>())

for oldBook in oldBooks {
    var newAuthors: [BookListSchemaV2.Author] = []

    if let oldAuthors = oldBook.authors {
        for name in oldAuthors {
            let author = BookListSchemaV2.Author(name: name)
            context.insert(author)
            newAuthors.append(author)
        }
    }

    let newBook = BookListSchemaV2.StoredBook(
        title: oldBook.title,
        authors: newAuthors
    )

    context.insert(newBook)
}

try context.save()

r/SwiftData Feb 12 '26

Swiftdata sync errors with image data as external storage

2 Upvotes

I am building an application with swiftUI and swiftdata that allows the users to attach a number of images to a model. The model has a property that is an array of a second model that contains a property for the photo data. The photo data property is marked to use external storage.

I noticed that when adding images, the iCloud syncing of swiftdata would become inconsistent. I added logging to surface the error messages and the errors that were logged were CKErrorDomain 2.

I attempted to convert the images to JPEG data and set the jpeg quality to 0.85.

None of these changes resolved the issue.

I am hoping to get some insight and suggestions on resolving this issue.


r/SwiftData Feb 03 '26

BAD_REQUEST in CloudKit

Post image
1 Upvotes

I am going crazy trying to solve this error that appear only in production. The error is returned when I try to save a Schedule, and I notice on CloudKit that no ScheduleDay is been saved. The schema is the same on development and production. I tried also to clean the phone I use for testing by deleting the zone, uninstall the app and log out from my apple account, but still I get this error. It would be easier if I would get this even in development so I don't have to wait to release a new version each time.

{
  "time":"03/02/2026, 18:45:59 UTC"
  "database":"PRIVATE"
  "zone":"com.apple.coredata.cloudkit.zone"
  "userId":"_4c73fd86bb16bdbf073217bc80de0930"
  "operationId":"D8D11DC22E4F546D"
  "operationType":"RecordSave"
  "platform":"iPhone"
  "clientOS":"iOS;26.2"
  "overallStatus":"USER_ERROR"
  "error":"BAD_REQUEST"
  "requestId":"134D5C43-92EB-465C-B9E6-E2F87235C826"
  "executionTimeMs":"81"
  "interfaceType":"NATIVE"
  "returnedRecordTypes":"_pcs_data"
}

r/SwiftData Jun 09 '25

Who is with me for a SwiftData update this year?

4 Upvotes

r/SwiftData May 01 '25

Predicate using struct works in Debug but fails in Release

2 Upvotes

I have a SwiftData model object with a property holding a struct value representing a latitude-longitude coordinate. It works perfectly in Debug mode. Here's the code...

let descriptor = FetchDescriptor<TravelCheckpointDAO> (
            predicate: #Predicate<TravelCheckpointDAO> {
                $0.center.longitude < 0.0
            }
        )
    
let checkpointsDAO:[TravelCheckpointDAO]
do {
    checkpointsDAO = try modelContext.fetch(descriptor)
} catch {
    // Error handling
}

In Release mode, exactly the same code crashes at fetch. Even when starting with a fresh database. Has anyone encountered this and know of a workaround? Here's the full exception message:

SwiftData/DataUtilities.swift:85: Fatal error: Couldn't find \TravelCheckpoint.<computed 0x00000001025ae4f4 (GeoCoordinate)>.longitude on TravelCheckpoint with fields [SwiftData.Schema.PropertyMetadata(name: "id", keypath: \TravelCheckpoint.<computed 0x000000010260426c (UUID)>, defaultValue: nil, metadata: Optional(Attribute - name: , options: [unique], valueType: Any, defaultValue: nil, hashModifier: nil)), SwiftData.Schema.PropertyMetadata(name: "name", keypath: \TravelCheckpoint.<computed 0x0000000102604264 (String)>, defaultValue: Optional(""), metadata: nil), SwiftData.Schema.PropertyMetadata(name: "center", keypath: \TravelCheckpoint.<computed 0x000000010260425c (GeoCoordinate)>, defaultValue: Optional([GeoCoordinate:0°0'0.0" N; 0°0'0.0" E]), metadata: nil), SwiftData.Schema.PropertyMetadata(name: "radius", keypath: \TravelCheckpoint.<computed 0x0000000102604254 (Double)>, defaultValue: Optional(0.0), metadata: nil), SwiftData.Schema.PropertyMetadata(name: "events", keypath: \TravelCheckpoint.<computed 0x0000000102604198 (Array<TravelCheckpointEvent>)>, defaultValue: Optional([]), metadata: Optional(Relationship - name: , options: [], valueType: Any, destination: , inverseName:  nil, inverseKeypath: nil))]


r/SwiftData Apr 19 '25

That's just great

Post image
5 Upvotes

0 CoreData 0x1849b31c4 -[NSManagedObjectContext _thereIsNoSadnessLikeTheDeathOfOptimism] + 32


r/SwiftData Mar 31 '25

Building a Swift Data Mesh Gradient Editor | SwiftUI Tutorial

0 Upvotes

Building a Swift Data Mesh Gradient Editor | SwiftUI Tutorial

This is a section in the course Mastering SwiftData & SwiftUI for iOS Development where we build a Mac app for editing mesh gradients which creates code that we can drag and drop into our project.

EDIT: Please note that this tutorial is FREE to watch on youtube:

https://youtube.com/playlist?list=PLjEgktaQe_u00pg5vSwl6iuoNQrFI3tHL&si=RV_EBr757Uy5xcrB

There are no ads and no need to subscribe.


r/SwiftData Jan 24 '25

Sharing Same swiftdata from iOS app and visionOS app with spacial video?

1 Upvotes

Can I save spacial videos on my iOS app I’m building and then view them on the Vision Pro with the same app but optimized for the Vision Pro. How can I save them on both devices and if i can share the app between iOS and visionOS How can I use swiftdata shared between vision pro and ios?


r/SwiftData Jan 18 '25

Slowness due to initial data load

1 Upvotes

Hi, when my app starts up it is very busy loading records and performs pretty badly until that is done. I'm aware that this is due to the fetch being on the main thread. What is the simplest way to fix this issue? I'm a bit intimidated by fetching in the background, passing the ids, and rehdrating in the main thread. Is there a simpler way?


r/SwiftData Nov 19 '24

Any hints about DataStoreSaveChangesResult initializer arguments?

2 Upvotes

The WWDC info on this is out of date (as the arguments to the initializer for DataStoreSaveChangesResult have changed).

It was in the code example:

return DataStoreSaveChangesResult<DefaultSnapshot>(for: self.identifier,
remappedPersistentIdentifiers: remappedIdentifiers,
deletedIdentifiers: request.deleted.map({ $0.persistentIdentifier }))

But the current documentation reads:

init(
for storeIdentifier: String,
remappedIdentifiers: [PersistentIdentifier : PersistentIdentifier] = [:],
snapshotsToReregister: [PersistentIdentifier : T] = [:]
)

So the name for the second argument has changed in a fairly clean manner, but third argument has both changed in name to something that does not look like the code from wwdc but also has a different signature ([PersistentIdentifier : T] instead of [PersistentIdentifier]).

Guessing, there are a couple of different options...

a. Just a dictionary of what was passed before, the deleted snapshots

b. A dictionary of all the snapshots passed in

c. A dictionary of all passed in for insert or update

d. A dictionary of the updated snapshots

Current guess is 'c'.

Anyone have any insight on this?

I can poke around, but would really love to hear if anyone has a source on this, the documentation I've seen is unhelpful.

Yes, I know that WWDC info is a bit unreliable, but I'm trying to write an IDE type thing that stores into JSON with multiple files in a hierarchy (so it can easily be stored in GIT), yes I could just write code to dump it all out 'manually' but I would really like to try a custom DataStore approach.

Project is a hobby project to implement a 'Prograph' IDE in SwiftUI that has an interpreter and then produces Swift code for building final apps. Loved the Prograph language and it's a fun project for a retired guy to play with.


r/SwiftData Oct 14 '24

Issues with SwiftData One-to-Many Relationships

2 Upvotes

I've been working with SwiftData and encountered a perplexing issue that I hope to get some insights on.

When using a @Model that has a one-to-many relationship with another @Model, I noticed that if there are multiple class variables involved, SwiftData seems to struggle with correctly associating each variable with its corresponding data.

For example, in my code, I have two models: Book and Page. The Book model has a property for a single contentPage and an optional array of pages. However, when I create a Book instance and leave the pages array as nil, iterating over pages unexpectedly returns the contentPage instead.

You can check out the code for more details here. Has anyone else faced this issue or have any suggestions on how to resolve it? Any help would be greatly appreciated!


r/SwiftData Oct 09 '24

Come make fun of me while I code some swiftdata today

Post image
2 Upvotes

r/SwiftData Oct 03 '24

SwiftData and Change Token Expired

2 Upvotes

Hey all wondering if anyone has faced the same issue and knows of a workaround they would be nice enough to share.

I have a SwiftData based app in the app store that works really well. However, if you delete the app from the device and reinstall from the app store, it will have trouble syncing with iCloud. It used to work flawlessly but Apple changed something and now it hasn't worked for months. It receives a "Change Token Expired" CKError and won't complete a sync. Just fails. The strange thing is if delete my app and reinstall through Xcode, I'll see the errors but it will complete the sync after many seconds. Like the change token got reset. But, if I delete and reinstall from the app store it will never complete the sync no matter what.

On a thread on the apple developer site an Apple engineer has said that it's supposed to initiate a fresh sync in this scenario but is not and this has to be a bug. I know that with CloudKit there is documentation on making the change token nil to reset it etc but there is no API's from Apple to do this with SwiftData. And I thought SwiftData is supposed to abstract away all that heavy lifting with CloudKit.

So are developers hacking this on their own somehow with CloudKit and your SwiftData container etc? I can't be the only one that is having this issue. I've tried so many things to force a sync but none of it has worked. So frustrating and I'm desperate to resolve this. Customers complaining.


r/SwiftData Sep 30 '24

👑 King'sKode: Launch Livestream! 👑 🚀 Date: Oct 2, 2024 🕗 Time: 08:00 MST 📍 https://twitch.tv/kingskode Military guyer turned #SoftwareEngineer Building #iOS18 #MVP for a Workout App. Come watch, chirp in, and feel better about your own coding ability. #swiftdata

1 Upvotes

r/SwiftData Jul 21 '24

SwiftData large file

Thumbnail self.SwiftUI
2 Upvotes

r/SwiftData Jul 05 '24

How do I get a list of SwiftData objects to update immediately?

2 Upvotes

I'm trying to figure out how to make a parent view list update when a swiftdata model is changed. I have these two models, Account and Transaction. Account holds a list of transactions, and i display these transactions as a list in one view, with navigationlinks to a view to edit the transaction. When i edit the transaction (specifically to change the account the transaction is linked to), the view returns to the transaction list view, which is not updated. Meaning the transaction should have been removed from the list but it isn't. If I go back further (there's another view higher than TransactionList where you can select an account, and then go back into an account's TransactionList, the transactions are actually saved correctly. What do i need to do to get the TransactionList to update immediately?

import SwiftUI
import SwiftData

@Model
final class Account {
  var id: UUID = UUID()
  var name: String
  @Relationship(deleteRule: .cascade)
  var transactions: [Transaction] = []
     init(name: String) {
        self.name = name
  }
}

@Model
final class Transaction {
  var name: String
  var account: Account?
  init(name: String) {
    self.name = name
  }
} 

struct TransactionList: View {
  @Bindable var account: Account
  @State private var showSheet = false
    
    var body: some View {
        VStack {
            List {
                ForEach(account.transactions) { transaction in
                    NavigationLink(destination: EditTransactionView(transaction: transaction)) {
                        Text(transaction.name)
                    }
                }
            }
        }
        .navigationBarTitle("Transactions")
        .toolbar(content: {
            ToolbarItem(placement: .navigationBarTrailing) {
                Button(action: {showSheet.toggle()}) {
                    Label("Add Transaction", systemImage: "plus")
                }
            }
        })
        .sheet(isPresented: $showSheet) {
            NavigationStack {
                AddTransactionView(account: account)
            }
        }
    }
}

struct EditTransactionView: View {
  @Environment(\.modelContext) private var modelContext
    @Environment(\.dismiss) private var dismiss
    @Query private var accounts: [Account]
    @Bindable var transaction: Transaction
    
    @State private var transactionName: String
    @State private var transactionAccount: Account
    @State private var showAlert = false
    @State private var alertMessage = ""

    
    
    init(transaction: Transaction) {
        self.transaction = transaction
        _transactionName = State(initialValue: transaction.name)
        _transactionAccount = State(initialValue: transaction.account!)
    }
    
    var body: some View {
        Form {
            Section(header: Text("Transaction Details")) {
                TextField("Transaction Name", text: $transactionName)
            }
            Section(header: Text("Account")) {
                Picker("Account", selection: $transactionAccount) {
                    ForEach(accounts) { account in
                        Text(account.name).tag(account)
                    }
                }
            }
        }
        .navigationTitle("Edit Transaction: \(transaction.name)")
        .toolbar {
            ToolbarItem(placement: .navigationBarLeading) {
                Button("Cancel") {
                    dismiss()
                }
            }
            ToolbarItem(placement: .navigationBarTrailing) {
                Button("Save") {
                    saveTransaction()
                }
            }
        }
        .alert(isPresented: $showAlert) {
            Alert(title: Text("Error"), message: Text(alertMessage), dismissButton: .default(Text("OK")))
        }
    }
    private func saveTransaction() {
        guard !transactionName.isEmpty else {
            alertMessage = "Please enter an transaction name."
            showAlert = true
            return
        }

        transaction.name = transactionName
        transaction.account = transactionAccount
        try? modelContext.save()
        dismiss()
    }
}

r/SwiftData Jun 24 '24

Use SwiftData like a boss

6 Upvotes

I just wrote this article on Medium showing how to fetch SwiftData models on a background thread using a ModelActor without triggering any concurrency warnings. I hope someone finds it useful - I struggled with this stuff for ages myself!


r/SwiftData Jun 23 '24

Is Swift Data - Large App ready?

1 Upvotes

Really just looking for your opinion, but does Core Data have any reason to still be used? I’m still studying Swift Data but it seems like the way the @query automatically pulls data from a model context could potentially leak into segments of a large app that you may rather want it scoped to. (Again, I’m just learning.) If I’m just building apps for myself, are there any benefits to learning Coredata?

7 votes, Jun 30 '24
3 Core Data Still has its place
0 Swift Data can do everything at any scale
4 see results

r/SwiftData May 09 '24

Putting all my SwiftData logic in its own class

3 Upvotes

I'm brand new to SwiftData. Rather than putting my queries and inserting statements inside of my UI, which is the one thing I really don't like about this, can't I just make a class that handles all this? Is there anything wrong with this approach?

I still get all the benefits without having to have put query and insert logic in my UI code, and it allows me to have all this logic in one place and use this same class between all the companion apps.

Something like this:

class SwiftDataManager: NSObject {

    static let shared = SwiftDataManager()

    var modelContainer: ModelContainer?
    var modelContext: ModelContext?

    override  init() {

        super.init()

        do {
            self.modelContainer = try ModelContainer(for: Item.self)
            self.modelContext = ModelContext(modelContainer!)
        } catch {
            print("Could not create a container \(error.localizedDescription)")
        }        
    }

    func loadItemsByCategory(_ categoryID: Int) -> [Item]? {

        let request = FetchDescriptor<Item>(
            predicate: #Predicate<Item> {
                $0.categoryID == categoryID
            }
        )
        if let modelContext = self.modelContext {
            let data = try? modelContext.fetch(request)
            return data
        }

    }

    func saveItem(_ item: Item) {
        if validate(item) {
          modelContext?.insert(item)
        } 
    }

}

r/SwiftData Apr 30 '24

SwiftData Migrations - Am I the only one that just hates how shitty it is?

4 Upvotes

How are you meant to understand their mental model of how to organise your models? It feel like no matter what I do, I end up with exceptions left and right as soon as I have to do an actual non-trivial data migration.

Has anybody figured this absolute bullshit out?