SwiftData

RSS for tag

Learn to write model code declaratively to add managed persistence and efficient model fetching.

SwiftData Documentation

Posts under SwiftData subtopic

Post

Replies

Boosts

Views

Activity

SwiftData + CloudKit schema evolution post release
I have a SwiftData + CloudKit app that is deployed to the Mac App Store. As a diagram my situation looks like: On my Mac, I have installed the App Store version of the App. When developing it I run the app via Xcode, so I can have a debug build running. The initial stable schema was deployed to CloudKit production before the App release. Now, when I change the SwiftData schema again and run the Debug app on my Mac What happens is that: The SwiftData local store is on the latest schema The CloudKit schema for development is automatically updated That’s all good, but if I run the App Store app version of my app. By default, it uses the same SwiftData store for both builds of the app, which are being synced to different CloudKit schemas for development and production at the same time. As a result, I get an unreliable state where I have seen data duplication as a result, or CloudKit syncing just breaks. Also, since I’m developing the app, the changes to the schema in development may not make it to production, so I don’t want to promote those changes to production. So my question: What’s the recommended way to evolve the schema for an app already on the App Store? I haven’t seen any example or session from Apple that tackles this -what I consider common- use case. I tried to have different CloudKit containers for a "Dev" and "Prod" builds, but that wasn’t the solution.
0
0
15
14h
How to detect if a migration is required?
Hello, With Core Data, we can use the isConfiguration(withName:compatibleWithStoreMetadata:) method on an NSManagedObjectModel alongside metadata(for:) on NSPersistentStoreCoordinator to check if the on-disk store is up to date or not. Is this the way to do it too with SwiftData or do we have an easier way to check if the on-disk store will need to migrate? I want to inform my users in the UI when the app launches (or from widgets or app intents). Regards, Axel
0
0
24
18h
Better alternative to WWDC's `withContinuousObservation` in View initializers for SwiftData?
Hi everyone, I was watching the "Code-along: Add persistence with SwiftData" session and noticed a strange architectural choice at the end. They track model side-effects directly inside a SwiftUI View's initializer like this: init(activity: Activity, isLast: Bool, isEditing: Bool) { activity.token = withContinuousObservation(options: .didSet) { event in // ... side effects here } } This feels like a significant architectural smell. SwiftUI views are transient structures with no guaranteed lifetime—they can be initialized dozens of times a second during standard layout passes. Furthermore, if multiple views display or interact with the same Activity, this tracking work gets duplicated redundantly. I understand this is a workaround because attaching a standard didSet directly to a stored property inside a @Model class doesn't trigger cleanly due to how the macro expands back-end storage. To keep this data-logic in the model layer where it belongs, I came up with an alternative that maps a custom computed property over a real stored attribute using. Here is the pattern: import SwiftUI import SwiftData @Model class Item { // 1. Persist the actual database column under an internal property name private var _title: String // 2. Expose a public computed property to intercept mutations var title: String { get { _title } set { // Updating the backing variable automatically fires the macro's observation hooks _title = newValue updatedAt = .now // Our derived side-effect! } } var updatedAt: Date init(title: String) { self._title = title self.updatedAt = .now } } Why I prefer this over the WWDC approach: Separation of Concerns: The model handles its own data dependencies (updatedAt), meaning the View layer remains purely declarative. Predictable Execution: The mutation logic runs exactly once per write, regardless of how many views are rendering or re-initializing around the object. No Manual Observation Setup: Because _title is a real, macro-backed attribute, SwiftData’s generated access and withMutation hooks are invoked naturally when the computed property reads or writes to it. We don't have to manually manage tokens or observation blocks. What do you all think? Are there any hidden gotchas to manipulating the schema mapping via originalName like this, or is this a vastly superior layout to WWDC's view-bound observation snippet? The downside is now the SQLIte column is _TITLE instead of TITLE. Is there any workaround for that? There doesn't seem to be @Attribute(columnName: "title")
1
1
46
19h
Dynamic Compound Predicates
This is relating to the question I have for the App Intents framework (see my question). I know that SwiftData started to support compound predicates with macOS 14.4/iOS 17.4 or later. But from what I understand they are not dynamic and are validated at compile time. Is there a way to update/construct predicates while the app is running? For example to create a search tab that allows searching and filtering for my items in the app.
2
0
123
1d
SwiftData predicate filtered by enum case
I have several Swift Data types with a property of type enum. Whenever I've tried to write a predicate returning data objects only of a certain enum case, the compiler throws an error from the macro at build time. (which I don't have handy, sorry...). Is this supported? And if so, how would you write the predicate? @Model public final class AlbumList { // ... public var listType: AlbumListType // ... } public enum AlbumListType: String, CaseIterable, Codable { case listener case dj }
4
2
149
1d
How to create @Query based on input
Overview I have a view B contains @Query for cars, now this @Query predicate depends on an input which is passed from view A. Current approach I am creating @Query in the init of view B by using _cars. Questions Now how can I compose @Query based on input from view A? Is my approach correct? In my approach Query will be created every time init gets called Or is there a better approach?
2
0
58
2d
SwiftData Predicate for optional to-many (as required by CloudKit) relationships crashes
Fails with "to-many key not allowed here" // parent.children?.contains(where: { // $0.name == "Abbiejean" // }) != nil parent.children.flatMap { children in children.contains(where: { $0.name == "Abbijean" }) } == true How are we supposed to query on relationships? This is a huge problem. This is a major limitation blocking migration of CoreData to SwiftData. We can do this with NSPredicate: let moodAnalysis = NSPredicate(format: "ANY moodAnalysis.labels.title == %@", label.description) let stateOfMinds = NSPredicate(format: "SUBQUERY(stateOfMinds, $x, SUBQUERY($x.labels, $y, $y.title == %@).@count > 0).@count > 0", label.description) The accepted answer on stack overflow is: you can't Document says that optionals are allowed in predicates The SwiftData team has made a big show of saying that we can use idiomatic swift for our predicates. But we cannot even filter on relationships when the container is backed by CloudKit... That should be a HUGE warning in the documentation. "For those of you who are considering a costly refactor from CoreData to SwiftData, and are currently using CloudKit, all relationships are mandatory optional arrays, and you can't write predicates on them"
4
0
344
3d
Sectioned fetching: beyond String keyPaths?
Hello, world! First and foremost, thank you for all the enhancements made to SwiftData and kudos to the team! In Thomas’ video demonstrating “What’s new in SwiftData”, I notice the keyPath (trip.destination) used to create sections in the list is a String. I can’t help but wonder if a keyPath of another data type could be used (like trip.startDate), were one to want to create sections based on whether a trip is past or upcoming for example? Thank you in advance for your much appreciated input! Zoé
2
0
122
3d
CoreData lightweight migration fails on iOS 26 only — "no such column: Z_110GROUPITEMS1"
We've spent several days diagnosing a CoreData migration crash that is iOS 26-specific and reproducible 100% of the time. Posting here in case others have hit this and because we believe it's an Apple bug worth documenting. Upgrading from our App Store build (CoreData model v10) to our latest TestFlight build (model v11) crashes on iOS 26 with: NSCocoaErrorDomain / Code 134110 no such column: "Z_110GROUPITEMS1" The same upgrade path on iOS 17 and iOS 18 works perfectly. What v10→v11 changes Two new entities added alphabetically early in the alphabet One new optional boolean attribute on an existing entity One new optional to-many relationship on the same existing entity All changes are lightweight-migration compatible. We use shouldMigrateStoreAutomatically = true and shouldInferMappingModelAutomatically = true Here's what we observed Adding two entities alphabetically shifts Z_ENT numbers for all subsequent entities. A central entity (EntityA) moves from Z_ENT 110 (v10) to Z_ENT 112 (v11). It has many-to-many relationships with four other entities (EntityB, EntityC, EntityD, EntityE), all using the same inverse relationship name: groupItems. Because multiple join tables reference EntityA via the same inverse name, CoreData appends a disambiguation suffix (1, 2, etc.) to column names in each join table. In v10, the relevant join tables are Z_110ENTITYB and Z_110ENTITYC, each with a column named Z_110GROUPITEMS + a suffix. -com.apple.CoreData.SQLDebug 3 prints: ALTER TABLE Z_112ENTITYB RENAME COLUMN Z_110GROUPITEMS1 TO Z_112GROUPITEMS1 But the actual column in a fresh iOS 26 v10 store is Z_110GROUPITEMS2. Column not found → crash. iOS 17/18 is consistent: both code paths use suffix 1 for Z_110ENTITYB and 2 for Z_110ENTITYC. Migration succeeds. To confirm We opened the SQLite store from a fresh iOS 26 v10 install and inspected the schema: CREATE TABLE Z_110ENTITYB ( Z_110GROUPITEMS2 INTEGER, Z_112ENTITYB INTEGER, PRIMARY KEY (Z_110GROUPITEMS2, Z_112ENTITYB) ); Then we manually renamed Z_110GROUPITEMS2 → Z_110GROUPITEMS1 and Z_110ENTITYC.Z_110GROUPITEMS1 → Z_110GROUPITEMS2 in the SQLite file. Re-ran the app — migration succeeded. The suffixes are literally swapped between what iOS 26 creates on fresh install vs. what iOS 26's migration engine expects. Our database has over 50 entities and we never before faced such an issue. This is not the first lightweight migration we are releasing after iOS 26 and that's what puzzled us. Why now?
2
0
106
4d
Fetch data in a time range, plus extend one more entry
I’m using Swift Charts in my app to display data in a visual way. For that (as well as some sum calculations) I’d like to create a fetch request that searches for all the data in a given time range plus one older and newer entry. Building a predicate that searches for a time range is easy, but how can I tell the fetch request that I would also like to have the first entry that comes before that time range and the first that comes after? I don’t know when these entries appear, so I can’t extend the time range. Example Let’s say I have the following data (timestamp – value): Feb 1, 2024 – 20 Oct 1, 2024 – 30 Jan 1, 2025 – 40 Sep 1, 2025 – 50 May 1, 2026 – 60 Oct 1, 2026 – 70 Now I want to search for the range Jan to Dec 2025. How can I retrieve the two entries that are in the range (No. 3 & 4) as well as the first entry before (No. 2) and the first after that (No. 5)? Without knowing the timestamp of No. 2 and 5. I’d appreciate some best practices or tips how to handle this special case. 🙏
1
0
103
4d
Migration Hash Mismatch
I'm migrating an existing Core Data app to SwiftData and encountering a persistent schema hash mismatch that prevents the store from loading. The Core Data store has been in production for years with version 4 of the model. I have two models, lets call the Crew and Astronaut Create is a parent in the to-many relationship to Astronaut, the child. When I try the migration, the Crew model‘s hash matches, but the Astronaut model’s mismatches. I also tried changing relationship parameters; deleteRule, maximumModelCount, inverse, originalName, and hashModifier. hashModifier changes the hash, but to a third value, so it does not appear to be a way to match the existing Core Data hash. So, is there a supported way for SwiftData to generate an optional to-one relationship that is Core Data hash-compatible with optional=YES minCount=1 maxCount=1? Or is a migration/rehash/copy step required before SwiftData can adopt this V4 store in place?
3
0
81
4d
SwiftData + public CloudKitDatabase?
Greetings, Thank you for SwiftData + new features. I am looking forward to the SwiftData Group Lab on Friday. How does the performance of SwiftData + CloudKit private database compare to CoreData + NSPersistenceCloudKitContainer? Also, will SwiftData + CloudKit support the CK public database, in the future? Thank you!
2
2
110
4d
889 CoreData errors in a SwiftData app of less than 30 lines
I have created a SwiftData iOS app from Paul Hudson's Hacking With Swift series in order to troubleshoot some SwiftData issues I am having in a separate app. I have raised > FB22925785 I have gone back to basics to try and problem solve so I have used the first part of an app of Paul's from [https://www.hackingwithswift.com/quick-start/swiftdata/defining-a-data-model-with-swiftdata] The App is very simple and only contains the following import SwiftData import SwiftUI @main struct iTour_from_scratchApp: App { var body: some Scene { WindowGroup { ContentView() .modelContainer(for: Destination.self) } } } The data is import SwiftData @Model class Destination { var name: String var details: String var date: Date var priority: Int init(name: String, details: String, date: Date, priority: Int) { self.name = name self.details = details self.date = date self.priority = priority } } The view is import SwiftUI struct ContentView: View { var body: some View { VStack { Image(systemName: "globe") .imageScale(.large) .foregroundStyle(.tint) Text("Hello, world!") } .padding() } } #Preview { ContentView() } When I try to run this, I am getting 889 lines of CoreData errors appearing in the Console and they start with CoreData: error: Failed to stat path '/Users/chrissantavy/Library/Developer/CoreSimulator/Devices/913BFD87-5FD8-47B9-AD0C-81238E74E89E/data/Containers/Data/Application/29586FDF-F08D-48E8-AF58-FD7BD5A30525/Library/Application Support/default.store', errno 2 / No such file or directory. CoreData: error: Executing as effective user 501 CoreData: error: Executing as effective user 501 CoreData: error: Sandbox access to file-write-create denied CoreData: error: Sandbox access to file-write-create denied CoreData: error: Failed to statfs file; errno 2 / No such file or directory. CoreData: error: Failed to statfs file; errno 2 / No such file or directory. CoreData: error: Information for file system CoreData: error: Information for file system CoreData: error: --------------------------- CoreData: error: --------------------------- CoreData: error: File system type: 0 CoreData: error: File system type: 0 CoreData: error: File system flags: 0 CoreData: error: File system flags: 0 CoreData: error: Total data blocks: 0 CoreData: error: Total data blocks: 0 CoreData: error: Free data blocks: 0 CoreData: error: Free data blocks: 0 CoreData: error: Free blocks for nonsuperuser: 0 CoreData: error: Free blocks for nonsuperuser: 0 CoreData: error: Total i-nodes: 0 CoreData: error: Total i-nodes: 0 CoreData: error: File system ID: 0, 0 CoreData: error: File system ID: 0, 0 CoreData: error: Free i-nodes: 0 CoreData: error: Free i-nodes: 0 CoreData: error: Owner UID: 0 CoreData: error: Owner UID: 0 CoreData: error: Filesystem type name: CoreData: error: Filesystem type name: CoreData: error: Mount on name: CoreData: error: Mount on name: CoreData: error: Mount from name: CoreData: error: Mount from name: CoreData: error: Failed to stat path '/Users/chrissantavy/Library/Developer/CoreSimulator/Devices/913BFD87-5FD8-47B9-AD0C-81238E74E89E/data/Containers/Data/Application/29586FDF-F08D-48E8-AF58-FD7BD5A30525/Library/Application Support', errno 2 / No such file or directory. CoreData: error: Failed to stat path '/Users/chrissantavy/Library/Developer/CoreSimulator/Devices/913BFD87-5FD8-47B9-AD0C-81238E74E89E/data/Containers/Data/Application/29586FDF-F08D-48E8-AF58-FD7BD5A30525/Library/Application Support', errno 2 / No such file or directory. CoreData: error: Executing as effective user 501 The full list of errors is attached iTour from scratch Part-1 errors.txt
1
0
93
4d
SwiftData: class inheritance without entity inheritance
In SwiftData, how can I have class inheritance without entity inheritance? My understanding is when models are subclassed they then share the same SQLite table allowing one Query to return multiple model types. However what if we don't require that functionality and only wish to share some overridable logic. I.e. share a base class implementation with multiple @Model subclasses but each model is in it's own SQLite table. E.g. say I want a savedAt timestamp field in every model and have the logic for setting it across all models. Or do some validation that calls super to check parent implementation is valid too. Maybe the validation behaviours can be done using protocols and extensions some how? Thanks!
1
0
81
4d
SwiftData @Query with a Custom (non-standard) Sort Criterion
I have a @Query which I would like to sort using a custom criterion. I would like to use an array of SortDescriptors where I can specify a key path and a CUSTOM SortComparator. (I.e., I can write SortComparators which do what I want, but I can't use them in a SortDescriptor because there is no initializer which takes a SortCompartor which is not a String.StandardComparator.) This is not a question about dynamic sorting, which has well-known solutions. I am trying to perform a sort which cannot be satisfied by any existing SortDescriptor (or array of SortDescriptors). Any thoughts about how to resolve this situation?
2
0
119
1w
SwiftData 'simple' migration failing
This is a long post, so let me start with a summary: I am attempting to implement what "ought to be" a simple SwiftData migration, and am receiving the following fatal error from the ModelContainer initializer: NSCocoaErrorDomain Code=134504 "Cannot use staged migration with an unknown model version." The crash occurs both in the Simulator and on a physical device. Both the original schema and the new schema load and run as expected if loaded from scratch — so I conclude the Models are OK; it is the migration from the original schema to the new schema which is the issue. I have reported this as FB22652791 and Technical Incident Case # 19893980. I have two model projects available — one contrived, the other using my actual SwiftData models. Now the Details I am developing a SwiftUI/SwiftData app. I am (currently) using Xcode 26.5-beta-3. I set up an alpha-test build using the following approach: public class DatabaseSchema { public let dbSchema: Schema = Schema([ Model1.self, ... , Model16.self ], version: Schema.Version(0, 9, 0)) public var modelContainer: ModelContainer { let container: ModelContainer let modelConfiguration = ModelConfiguration(schema: dbSchema, isStoredInMemoryOnly: false) do { container = try ModelContainer(for: dbSchema, migrationPlan: nil, configurations: [modelConfiguration]) } catch { fatalError("Failed to creae model conainer") } return container } This defines database version 0.9. For version 1.0, I made three changes to the database: added an attribute of type String to Model2. added three attributes of type [Struct], where Struct conforms to Codable, Equatable and Hashable to Model3, and added a new model (which I'll call Model17) I define two schemas: public enum Schema090: VersionedSchema { public static var versionIdentifier = Schema.Version(0, 9, 0) public static var models: [any PersistentModel.Type] = [ Model1.self, Schema090.Model2.self, Schema090.Model3.self, ... ] } and public enum Schema100: VersionedSchema { public static var versionIdentifier = Schema.Version(1, 0, 0) public static var models: [any PersistentModel.Type] = [ Model1.swift, Schema100.Model2.self, Schema100.Model3.self, ..., Model16.self, Schema100.Model17.self ] } For models that changed, I use the following approach: public typealias Model3 = Schema100.Model3 extension Schema090 { @Model final class Model3 { ... } public init() { ... } } extension Schema100 { @Model final class Model3 { ... <added attributes, initialized> } public init() { ... } } The DatabaseSchema class was modified as follows: public class DatabaseSchema { public let dbSchema: Schema = Schema([ Model1.self, Schema100.Model2.self, Schema100.Model3.self, ... , Model16.self, Schema100.Model17.self ], version: Schema.Version(1, 0, 0)) public var modelContainer: ModelContainer { let container: ModelContainer let modelConfiguration = ModelConfiguration(schema: dbSchema, isStoredInMemoryOnly: false) do { container = try ModelContainer(for: dbSchema, migrationPlan: MigrationPlan.self, configurations: [modelConfiguration]) } catch { fatalError("Failed to creae model conainer") } return container } where the migration plan is the trivial custom migration that makes sure that all added attributes of existing records are properly initialized. enum MigrationPlan: SchemaMigrationPlan { static var schemas: [any VersionedSchema.Type] = [ Schema090.self, Schema100.self ] static var stages: [MigrationStage] = [version090ToVersion100] static let version090ToVersion100 = MigrationStage(fromVersion: Schema090.self, toVersion: Schema100.self, willMigrate: { _ in }, didMigrate: { context in let models = try context.fetch( FetchDescriptor<Schema100.Model3>()) for model in models { < initial the added attributes > { try context.save() }) } This is all simple stuff. Nothing particularly fancy here. But running this code always crashes in the ModelContainer initializer. In my two sample projects, I get two different error messages — in the contrived example, the error message is Code=134110 "An error occurred during persistent store migration." reason=Cannot migrate store in-place: Validation error missing attribute values on mandatory destination attribute, ... and in the sample project that uses my actual data model, I get NSCocoaErrorDomain Code=134504 "Cannot use staged migration with an unknown model version." My Thoughts Since obviously most folks are doing SwiftData migrations without the problems I am experiencing, the obvious possibilities are I'm doing something stupid that I just don't see. There is a problem because the original schema was given a version value of Schema.Version(0, 9, 0). (i.e., major version number was 0) There is a problem because I am adding an attribute of type [Struct] where Struct is Codable, Hashable, and Equatable. I.e., migration isn't working properly with attributes which are stored as their codable representations. Or maybe something else? In any case, any help you can offer would be greatly appreciated.
7
0
694
1w
TestFlight build crashes from fetch descriptor
I have a FetchDescriptor that uses starts(with:) which works fine in debug builds but crashes in TestFlight and archive. For background information I'm using iCloud and model inheritance where the property being used in fetch descriptor is defined on the superclass, the fetch descriptor is for the subclass. Implementation: static func fetchDescriptor(nameStartingWith prefix: String) -> FetchDescriptor<ColorAsset> { let predicate = #Predicate<ColorAsset> { asset in asset.name.starts(with: prefix) } return FetchDescriptor<ColorAsset>(predicate: predicate) } @Model public class Asset: Identifiable { // MARK: - Properties var name: String = "" .... } @available(macOS 26.0, *) @Model public class ColorAsset: Asset { ... }
4
1
445
2w
SwiftData crash on new property (Could not cast...)
I have a small example where adding a new property to a persisted Codable struct causes a crash on launch instead of decoding the missing property using its default value. Steps Run this app once and press "Insert Event" to persist data: import SwiftUI import SwiftData @main struct SwiftDataCrash: App { var body: some Scene { WindowGroup { ContentView() } .modelContainer(for: Event.self) } } struct ContentView: View { @Environment(\.modelContext) private var modelContext @Query private var events: [Event] var body: some View { VStack(spacing: 12) { Text("Events: \(events.count)") Button("Insert Event") { let event = Event( recurrence: Recurrence( interval: 1 ) ) modelContext.insert(event) try? modelContext.save() } List(events) { event in Text(String(describing: event.recurrence)) } } .padding() } } @Model final class Event { var recurrence: Recurrence? = nil init(recurrence: Recurrence? = nil) { self.recurrence = recurrence } } struct Recurrence: Codable { var interval: Int // STEP 2: // After first run + inserting an Event, uncomment this and run again. // Expected: old data decodes with default [] // Actual: SwiftData may crash while reading Event.recurrence // // var exceptionDates: [Date] = [] } Then uncomment: var exceptionDates: [Date] = [] and run again without deleting the store. Actual result App crashes on launch with: Could not cast value of type 'Swift.Optional<Any>' to 'Swift.Array<Foundation.Date>' The crash appears to happen inside generated SwiftData persisted-property getter code. Expected result I expected the old persisted Recurrence values to decode with: exceptionDates == [] Is this expected behavior or a SwiftData bug?
2
0
296
2w
Crash when adding large JSON data to SwiftData: Could not cast value of type '__NSCFBoolean' to 'NSString'
Within the app main struct, the SwiftData modelContainer is created by fetching and decoding JSON from remote site. The decoded data is inserted into the modelContext. Immediately thereafter, the app crashes with the error Could not cast value of type '__NSCFBoolean' to 'NSString' . I have run the JSON from the site through JSON lint and it is correctly structured. The JSON data is structured as follows: Overview object which includes a Result object which includes a List Array. Each List object includes a Books Array. I have run the app through AI and the result indicates that there is data corruption when adding the data to the database. The AI rewrote the code such that the book data is encoded into a data blob and then adds the data to the database, instead of adding the individual books (which is extensive.) This approach works without crashing, but I would like to find out if this is indeed a SwiftData issue.
4
0
185
Jul ’25
SwiftData + CloudKit schema evolution post release
I have a SwiftData + CloudKit app that is deployed to the Mac App Store. As a diagram my situation looks like: On my Mac, I have installed the App Store version of the App. When developing it I run the app via Xcode, so I can have a debug build running. The initial stable schema was deployed to CloudKit production before the App release. Now, when I change the SwiftData schema again and run the Debug app on my Mac What happens is that: The SwiftData local store is on the latest schema The CloudKit schema for development is automatically updated That’s all good, but if I run the App Store app version of my app. By default, it uses the same SwiftData store for both builds of the app, which are being synced to different CloudKit schemas for development and production at the same time. As a result, I get an unreliable state where I have seen data duplication as a result, or CloudKit syncing just breaks. Also, since I’m developing the app, the changes to the schema in development may not make it to production, so I don’t want to promote those changes to production. So my question: What’s the recommended way to evolve the schema for an app already on the App Store? I haven’t seen any example or session from Apple that tackles this -what I consider common- use case. I tried to have different CloudKit containers for a "Dev" and "Prod" builds, but that wasn’t the solution.
Replies
0
Boosts
0
Views
15
Activity
14h
How to detect if a migration is required?
Hello, With Core Data, we can use the isConfiguration(withName:compatibleWithStoreMetadata:) method on an NSManagedObjectModel alongside metadata(for:) on NSPersistentStoreCoordinator to check if the on-disk store is up to date or not. Is this the way to do it too with SwiftData or do we have an easier way to check if the on-disk store will need to migrate? I want to inform my users in the UI when the app launches (or from widgets or app intents). Regards, Axel
Replies
0
Boosts
0
Views
24
Activity
18h
Better alternative to WWDC's `withContinuousObservation` in View initializers for SwiftData?
Hi everyone, I was watching the "Code-along: Add persistence with SwiftData" session and noticed a strange architectural choice at the end. They track model side-effects directly inside a SwiftUI View's initializer like this: init(activity: Activity, isLast: Bool, isEditing: Bool) { activity.token = withContinuousObservation(options: .didSet) { event in // ... side effects here } } This feels like a significant architectural smell. SwiftUI views are transient structures with no guaranteed lifetime—they can be initialized dozens of times a second during standard layout passes. Furthermore, if multiple views display or interact with the same Activity, this tracking work gets duplicated redundantly. I understand this is a workaround because attaching a standard didSet directly to a stored property inside a @Model class doesn't trigger cleanly due to how the macro expands back-end storage. To keep this data-logic in the model layer where it belongs, I came up with an alternative that maps a custom computed property over a real stored attribute using. Here is the pattern: import SwiftUI import SwiftData @Model class Item { // 1. Persist the actual database column under an internal property name private var _title: String // 2. Expose a public computed property to intercept mutations var title: String { get { _title } set { // Updating the backing variable automatically fires the macro's observation hooks _title = newValue updatedAt = .now // Our derived side-effect! } } var updatedAt: Date init(title: String) { self._title = title self.updatedAt = .now } } Why I prefer this over the WWDC approach: Separation of Concerns: The model handles its own data dependencies (updatedAt), meaning the View layer remains purely declarative. Predictable Execution: The mutation logic runs exactly once per write, regardless of how many views are rendering or re-initializing around the object. No Manual Observation Setup: Because _title is a real, macro-backed attribute, SwiftData’s generated access and withMutation hooks are invoked naturally when the computed property reads or writes to it. We don't have to manually manage tokens or observation blocks. What do you all think? Are there any hidden gotchas to manipulating the schema mapping via originalName like this, or is this a vastly superior layout to WWDC's view-bound observation snippet? The downside is now the SQLIte column is _TITLE instead of TITLE. Is there any workaround for that? There doesn't seem to be @Attribute(columnName: "title")
Replies
1
Boosts
1
Views
46
Activity
19h
Dynamic Compound Predicates
This is relating to the question I have for the App Intents framework (see my question). I know that SwiftData started to support compound predicates with macOS 14.4/iOS 17.4 or later. But from what I understand they are not dynamic and are validated at compile time. Is there a way to update/construct predicates while the app is running? For example to create a search tab that allows searching and filtering for my items in the app.
Replies
2
Boosts
0
Views
123
Activity
1d
SwiftData predicate filtered by enum case
I have several Swift Data types with a property of type enum. Whenever I've tried to write a predicate returning data objects only of a certain enum case, the compiler throws an error from the macro at build time. (which I don't have handy, sorry...). Is this supported? And if so, how would you write the predicate? @Model public final class AlbumList { // ... public var listType: AlbumListType // ... } public enum AlbumListType: String, CaseIterable, Codable { case listener case dj }
Replies
4
Boosts
2
Views
149
Activity
1d
How to create @Query based on input
Overview I have a view B contains @Query for cars, now this @Query predicate depends on an input which is passed from view A. Current approach I am creating @Query in the init of view B by using _cars. Questions Now how can I compose @Query based on input from view A? Is my approach correct? In my approach Query will be created every time init gets called Or is there a better approach?
Replies
2
Boosts
0
Views
58
Activity
2d
Aggregate functions in SwiftData
Hi, does SwiftData supports aggregate functions through NSExpression for operations like SUM, AVG, MIN, and MAX?
Replies
2
Boosts
0
Views
118
Activity
3d
SwiftData Predicate for optional to-many (as required by CloudKit) relationships crashes
Fails with "to-many key not allowed here" // parent.children?.contains(where: { // $0.name == "Abbiejean" // }) != nil parent.children.flatMap { children in children.contains(where: { $0.name == "Abbijean" }) } == true How are we supposed to query on relationships? This is a huge problem. This is a major limitation blocking migration of CoreData to SwiftData. We can do this with NSPredicate: let moodAnalysis = NSPredicate(format: "ANY moodAnalysis.labels.title == %@", label.description) let stateOfMinds = NSPredicate(format: "SUBQUERY(stateOfMinds, $x, SUBQUERY($x.labels, $y, $y.title == %@).@count > 0).@count > 0", label.description) The accepted answer on stack overflow is: you can't Document says that optionals are allowed in predicates The SwiftData team has made a big show of saying that we can use idiomatic swift for our predicates. But we cannot even filter on relationships when the container is backed by CloudKit... That should be a HUGE warning in the documentation. "For those of you who are considering a costly refactor from CoreData to SwiftData, and are currently using CloudKit, all relationships are mandatory optional arrays, and you can't write predicates on them"
Replies
4
Boosts
0
Views
344
Activity
3d
Sectioned fetching: beyond String keyPaths?
Hello, world! First and foremost, thank you for all the enhancements made to SwiftData and kudos to the team! In Thomas’ video demonstrating “What’s new in SwiftData”, I notice the keyPath (trip.destination) used to create sections in the list is a String. I can’t help but wonder if a keyPath of another data type could be used (like trip.startDate), were one to want to create sections based on whether a trip is past or upcoming for example? Thank you in advance for your much appreciated input! Zoé
Replies
2
Boosts
0
Views
122
Activity
3d
CoreData lightweight migration fails on iOS 26 only — "no such column: Z_110GROUPITEMS1"
We've spent several days diagnosing a CoreData migration crash that is iOS 26-specific and reproducible 100% of the time. Posting here in case others have hit this and because we believe it's an Apple bug worth documenting. Upgrading from our App Store build (CoreData model v10) to our latest TestFlight build (model v11) crashes on iOS 26 with: NSCocoaErrorDomain / Code 134110 no such column: "Z_110GROUPITEMS1" The same upgrade path on iOS 17 and iOS 18 works perfectly. What v10→v11 changes Two new entities added alphabetically early in the alphabet One new optional boolean attribute on an existing entity One new optional to-many relationship on the same existing entity All changes are lightweight-migration compatible. We use shouldMigrateStoreAutomatically = true and shouldInferMappingModelAutomatically = true Here's what we observed Adding two entities alphabetically shifts Z_ENT numbers for all subsequent entities. A central entity (EntityA) moves from Z_ENT 110 (v10) to Z_ENT 112 (v11). It has many-to-many relationships with four other entities (EntityB, EntityC, EntityD, EntityE), all using the same inverse relationship name: groupItems. Because multiple join tables reference EntityA via the same inverse name, CoreData appends a disambiguation suffix (1, 2, etc.) to column names in each join table. In v10, the relevant join tables are Z_110ENTITYB and Z_110ENTITYC, each with a column named Z_110GROUPITEMS + a suffix. -com.apple.CoreData.SQLDebug 3 prints: ALTER TABLE Z_112ENTITYB RENAME COLUMN Z_110GROUPITEMS1 TO Z_112GROUPITEMS1 But the actual column in a fresh iOS 26 v10 store is Z_110GROUPITEMS2. Column not found → crash. iOS 17/18 is consistent: both code paths use suffix 1 for Z_110ENTITYB and 2 for Z_110ENTITYC. Migration succeeds. To confirm We opened the SQLite store from a fresh iOS 26 v10 install and inspected the schema: CREATE TABLE Z_110ENTITYB ( Z_110GROUPITEMS2 INTEGER, Z_112ENTITYB INTEGER, PRIMARY KEY (Z_110GROUPITEMS2, Z_112ENTITYB) ); Then we manually renamed Z_110GROUPITEMS2 → Z_110GROUPITEMS1 and Z_110ENTITYC.Z_110GROUPITEMS1 → Z_110GROUPITEMS2 in the SQLite file. Re-ran the app — migration succeeded. The suffixes are literally swapped between what iOS 26 creates on fresh install vs. what iOS 26's migration engine expects. Our database has over 50 entities and we never before faced such an issue. This is not the first lightweight migration we are releasing after iOS 26 and that's what puzzled us. Why now?
Replies
2
Boosts
0
Views
106
Activity
4d
Fetch data in a time range, plus extend one more entry
I’m using Swift Charts in my app to display data in a visual way. For that (as well as some sum calculations) I’d like to create a fetch request that searches for all the data in a given time range plus one older and newer entry. Building a predicate that searches for a time range is easy, but how can I tell the fetch request that I would also like to have the first entry that comes before that time range and the first that comes after? I don’t know when these entries appear, so I can’t extend the time range. Example Let’s say I have the following data (timestamp – value): Feb 1, 2024 – 20 Oct 1, 2024 – 30 Jan 1, 2025 – 40 Sep 1, 2025 – 50 May 1, 2026 – 60 Oct 1, 2026 – 70 Now I want to search for the range Jan to Dec 2025. How can I retrieve the two entries that are in the range (No. 3 & 4) as well as the first entry before (No. 2) and the first after that (No. 5)? Without knowing the timestamp of No. 2 and 5. I’d appreciate some best practices or tips how to handle this special case. 🙏
Replies
1
Boosts
0
Views
103
Activity
4d
Migration Hash Mismatch
I'm migrating an existing Core Data app to SwiftData and encountering a persistent schema hash mismatch that prevents the store from loading. The Core Data store has been in production for years with version 4 of the model. I have two models, lets call the Crew and Astronaut Create is a parent in the to-many relationship to Astronaut, the child. When I try the migration, the Crew model‘s hash matches, but the Astronaut model’s mismatches. I also tried changing relationship parameters; deleteRule, maximumModelCount, inverse, originalName, and hashModifier. hashModifier changes the hash, but to a third value, so it does not appear to be a way to match the existing Core Data hash. So, is there a supported way for SwiftData to generate an optional to-one relationship that is Core Data hash-compatible with optional=YES minCount=1 maxCount=1? Or is a migration/rehash/copy step required before SwiftData can adopt this V4 store in place?
Replies
3
Boosts
0
Views
81
Activity
4d
SwiftData + public CloudKitDatabase?
Greetings, Thank you for SwiftData + new features. I am looking forward to the SwiftData Group Lab on Friday. How does the performance of SwiftData + CloudKit private database compare to CoreData + NSPersistenceCloudKitContainer? Also, will SwiftData + CloudKit support the CK public database, in the future? Thank you!
Replies
2
Boosts
2
Views
110
Activity
4d
889 CoreData errors in a SwiftData app of less than 30 lines
I have created a SwiftData iOS app from Paul Hudson's Hacking With Swift series in order to troubleshoot some SwiftData issues I am having in a separate app. I have raised > FB22925785 I have gone back to basics to try and problem solve so I have used the first part of an app of Paul's from [https://www.hackingwithswift.com/quick-start/swiftdata/defining-a-data-model-with-swiftdata] The App is very simple and only contains the following import SwiftData import SwiftUI @main struct iTour_from_scratchApp: App { var body: some Scene { WindowGroup { ContentView() .modelContainer(for: Destination.self) } } } The data is import SwiftData @Model class Destination { var name: String var details: String var date: Date var priority: Int init(name: String, details: String, date: Date, priority: Int) { self.name = name self.details = details self.date = date self.priority = priority } } The view is import SwiftUI struct ContentView: View { var body: some View { VStack { Image(systemName: "globe") .imageScale(.large) .foregroundStyle(.tint) Text("Hello, world!") } .padding() } } #Preview { ContentView() } When I try to run this, I am getting 889 lines of CoreData errors appearing in the Console and they start with CoreData: error: Failed to stat path '/Users/chrissantavy/Library/Developer/CoreSimulator/Devices/913BFD87-5FD8-47B9-AD0C-81238E74E89E/data/Containers/Data/Application/29586FDF-F08D-48E8-AF58-FD7BD5A30525/Library/Application Support/default.store', errno 2 / No such file or directory. CoreData: error: Executing as effective user 501 CoreData: error: Executing as effective user 501 CoreData: error: Sandbox access to file-write-create denied CoreData: error: Sandbox access to file-write-create denied CoreData: error: Failed to statfs file; errno 2 / No such file or directory. CoreData: error: Failed to statfs file; errno 2 / No such file or directory. CoreData: error: Information for file system CoreData: error: Information for file system CoreData: error: --------------------------- CoreData: error: --------------------------- CoreData: error: File system type: 0 CoreData: error: File system type: 0 CoreData: error: File system flags: 0 CoreData: error: File system flags: 0 CoreData: error: Total data blocks: 0 CoreData: error: Total data blocks: 0 CoreData: error: Free data blocks: 0 CoreData: error: Free data blocks: 0 CoreData: error: Free blocks for nonsuperuser: 0 CoreData: error: Free blocks for nonsuperuser: 0 CoreData: error: Total i-nodes: 0 CoreData: error: Total i-nodes: 0 CoreData: error: File system ID: 0, 0 CoreData: error: File system ID: 0, 0 CoreData: error: Free i-nodes: 0 CoreData: error: Free i-nodes: 0 CoreData: error: Owner UID: 0 CoreData: error: Owner UID: 0 CoreData: error: Filesystem type name: CoreData: error: Filesystem type name: CoreData: error: Mount on name: CoreData: error: Mount on name: CoreData: error: Mount from name: CoreData: error: Mount from name: CoreData: error: Failed to stat path '/Users/chrissantavy/Library/Developer/CoreSimulator/Devices/913BFD87-5FD8-47B9-AD0C-81238E74E89E/data/Containers/Data/Application/29586FDF-F08D-48E8-AF58-FD7BD5A30525/Library/Application Support', errno 2 / No such file or directory. CoreData: error: Failed to stat path '/Users/chrissantavy/Library/Developer/CoreSimulator/Devices/913BFD87-5FD8-47B9-AD0C-81238E74E89E/data/Containers/Data/Application/29586FDF-F08D-48E8-AF58-FD7BD5A30525/Library/Application Support', errno 2 / No such file or directory. CoreData: error: Executing as effective user 501 The full list of errors is attached iTour from scratch Part-1 errors.txt
Replies
1
Boosts
0
Views
93
Activity
4d
SwiftData: class inheritance without entity inheritance
In SwiftData, how can I have class inheritance without entity inheritance? My understanding is when models are subclassed they then share the same SQLite table allowing one Query to return multiple model types. However what if we don't require that functionality and only wish to share some overridable logic. I.e. share a base class implementation with multiple @Model subclasses but each model is in it's own SQLite table. E.g. say I want a savedAt timestamp field in every model and have the logic for setting it across all models. Or do some validation that calls super to check parent implementation is valid too. Maybe the validation behaviours can be done using protocols and extensions some how? Thanks!
Replies
1
Boosts
0
Views
81
Activity
4d
SwiftData @Query with a Custom (non-standard) Sort Criterion
I have a @Query which I would like to sort using a custom criterion. I would like to use an array of SortDescriptors where I can specify a key path and a CUSTOM SortComparator. (I.e., I can write SortComparators which do what I want, but I can't use them in a SortDescriptor because there is no initializer which takes a SortCompartor which is not a String.StandardComparator.) This is not a question about dynamic sorting, which has well-known solutions. I am trying to perform a sort which cannot be satisfied by any existing SortDescriptor (or array of SortDescriptors). Any thoughts about how to resolve this situation?
Replies
2
Boosts
0
Views
119
Activity
1w
SwiftData 'simple' migration failing
This is a long post, so let me start with a summary: I am attempting to implement what "ought to be" a simple SwiftData migration, and am receiving the following fatal error from the ModelContainer initializer: NSCocoaErrorDomain Code=134504 "Cannot use staged migration with an unknown model version." The crash occurs both in the Simulator and on a physical device. Both the original schema and the new schema load and run as expected if loaded from scratch — so I conclude the Models are OK; it is the migration from the original schema to the new schema which is the issue. I have reported this as FB22652791 and Technical Incident Case # 19893980. I have two model projects available — one contrived, the other using my actual SwiftData models. Now the Details I am developing a SwiftUI/SwiftData app. I am (currently) using Xcode 26.5-beta-3. I set up an alpha-test build using the following approach: public class DatabaseSchema { public let dbSchema: Schema = Schema([ Model1.self, ... , Model16.self ], version: Schema.Version(0, 9, 0)) public var modelContainer: ModelContainer { let container: ModelContainer let modelConfiguration = ModelConfiguration(schema: dbSchema, isStoredInMemoryOnly: false) do { container = try ModelContainer(for: dbSchema, migrationPlan: nil, configurations: [modelConfiguration]) } catch { fatalError("Failed to creae model conainer") } return container } This defines database version 0.9. For version 1.0, I made three changes to the database: added an attribute of type String to Model2. added three attributes of type [Struct], where Struct conforms to Codable, Equatable and Hashable to Model3, and added a new model (which I'll call Model17) I define two schemas: public enum Schema090: VersionedSchema { public static var versionIdentifier = Schema.Version(0, 9, 0) public static var models: [any PersistentModel.Type] = [ Model1.self, Schema090.Model2.self, Schema090.Model3.self, ... ] } and public enum Schema100: VersionedSchema { public static var versionIdentifier = Schema.Version(1, 0, 0) public static var models: [any PersistentModel.Type] = [ Model1.swift, Schema100.Model2.self, Schema100.Model3.self, ..., Model16.self, Schema100.Model17.self ] } For models that changed, I use the following approach: public typealias Model3 = Schema100.Model3 extension Schema090 { @Model final class Model3 { ... } public init() { ... } } extension Schema100 { @Model final class Model3 { ... <added attributes, initialized> } public init() { ... } } The DatabaseSchema class was modified as follows: public class DatabaseSchema { public let dbSchema: Schema = Schema([ Model1.self, Schema100.Model2.self, Schema100.Model3.self, ... , Model16.self, Schema100.Model17.self ], version: Schema.Version(1, 0, 0)) public var modelContainer: ModelContainer { let container: ModelContainer let modelConfiguration = ModelConfiguration(schema: dbSchema, isStoredInMemoryOnly: false) do { container = try ModelContainer(for: dbSchema, migrationPlan: MigrationPlan.self, configurations: [modelConfiguration]) } catch { fatalError("Failed to creae model conainer") } return container } where the migration plan is the trivial custom migration that makes sure that all added attributes of existing records are properly initialized. enum MigrationPlan: SchemaMigrationPlan { static var schemas: [any VersionedSchema.Type] = [ Schema090.self, Schema100.self ] static var stages: [MigrationStage] = [version090ToVersion100] static let version090ToVersion100 = MigrationStage(fromVersion: Schema090.self, toVersion: Schema100.self, willMigrate: { _ in }, didMigrate: { context in let models = try context.fetch( FetchDescriptor<Schema100.Model3>()) for model in models { < initial the added attributes > { try context.save() }) } This is all simple stuff. Nothing particularly fancy here. But running this code always crashes in the ModelContainer initializer. In my two sample projects, I get two different error messages — in the contrived example, the error message is Code=134110 "An error occurred during persistent store migration." reason=Cannot migrate store in-place: Validation error missing attribute values on mandatory destination attribute, ... and in the sample project that uses my actual data model, I get NSCocoaErrorDomain Code=134504 "Cannot use staged migration with an unknown model version." My Thoughts Since obviously most folks are doing SwiftData migrations without the problems I am experiencing, the obvious possibilities are I'm doing something stupid that I just don't see. There is a problem because the original schema was given a version value of Schema.Version(0, 9, 0). (i.e., major version number was 0) There is a problem because I am adding an attribute of type [Struct] where Struct is Codable, Hashable, and Equatable. I.e., migration isn't working properly with attributes which are stored as their codable representations. Or maybe something else? In any case, any help you can offer would be greatly appreciated.
Replies
7
Boosts
0
Views
694
Activity
1w
TestFlight build crashes from fetch descriptor
I have a FetchDescriptor that uses starts(with:) which works fine in debug builds but crashes in TestFlight and archive. For background information I'm using iCloud and model inheritance where the property being used in fetch descriptor is defined on the superclass, the fetch descriptor is for the subclass. Implementation: static func fetchDescriptor(nameStartingWith prefix: String) -> FetchDescriptor<ColorAsset> { let predicate = #Predicate<ColorAsset> { asset in asset.name.starts(with: prefix) } return FetchDescriptor<ColorAsset>(predicate: predicate) } @Model public class Asset: Identifiable { // MARK: - Properties var name: String = "" .... } @available(macOS 26.0, *) @Model public class ColorAsset: Asset { ... }
Replies
4
Boosts
1
Views
445
Activity
2w
SwiftData crash on new property (Could not cast...)
I have a small example where adding a new property to a persisted Codable struct causes a crash on launch instead of decoding the missing property using its default value. Steps Run this app once and press "Insert Event" to persist data: import SwiftUI import SwiftData @main struct SwiftDataCrash: App { var body: some Scene { WindowGroup { ContentView() } .modelContainer(for: Event.self) } } struct ContentView: View { @Environment(\.modelContext) private var modelContext @Query private var events: [Event] var body: some View { VStack(spacing: 12) { Text("Events: \(events.count)") Button("Insert Event") { let event = Event( recurrence: Recurrence( interval: 1 ) ) modelContext.insert(event) try? modelContext.save() } List(events) { event in Text(String(describing: event.recurrence)) } } .padding() } } @Model final class Event { var recurrence: Recurrence? = nil init(recurrence: Recurrence? = nil) { self.recurrence = recurrence } } struct Recurrence: Codable { var interval: Int // STEP 2: // After first run + inserting an Event, uncomment this and run again. // Expected: old data decodes with default [] // Actual: SwiftData may crash while reading Event.recurrence // // var exceptionDates: [Date] = [] } Then uncomment: var exceptionDates: [Date] = [] and run again without deleting the store. Actual result App crashes on launch with: Could not cast value of type 'Swift.Optional<Any>' to 'Swift.Array<Foundation.Date>' The crash appears to happen inside generated SwiftData persisted-property getter code. Expected result I expected the old persisted Recurrence values to decode with: exceptionDates == [] Is this expected behavior or a SwiftData bug?
Replies
2
Boosts
0
Views
296
Activity
2w
Crash when adding large JSON data to SwiftData: Could not cast value of type '__NSCFBoolean' to 'NSString'
Within the app main struct, the SwiftData modelContainer is created by fetching and decoding JSON from remote site. The decoded data is inserted into the modelContext. Immediately thereafter, the app crashes with the error Could not cast value of type '__NSCFBoolean' to 'NSString' . I have run the JSON from the site through JSON lint and it is correctly structured. The JSON data is structured as follows: Overview object which includes a Result object which includes a List Array. Each List object includes a Books Array. I have run the app through AI and the result indicates that there is data corruption when adding the data to the database. The AI rewrote the code such that the book data is encoded into a data blob and then adds the data to the database, instead of adding the individual books (which is extensive.) This approach works without crashing, but I would like to find out if this is indeed a SwiftData issue.
Replies
4
Boosts
0
Views
185
Activity
Jul ’25