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

Best practices
Hi everyone, I'm Alexsander. My friends call me Lexie. I have been working as software developer since 6 years ago, I have a lot of experience with Java and I started working with Angular since the last year. I am new in the Apple ecosystem and I have a question about best practices in full native Swift apps. There is any source (blogs, youtube channels, books, et al.) where I can understand the best practices? Like, I've heard about MVVM to scalable apps but I don't know exactly how to apply it. I think it's because usually I do not have my front-end components in the same project of my backend. I've been watching some videos from Apple Developer youtube channel and they are absolutely amazing, but they only keep teaching people to use the "raw" resources, not matching with the best practices. For example, I saw using swift data we do not need to write any SQL Query, unlike Java Ecossystem where even we use a ORM we usually write our queries natively, whether creating a table or fetching data.
0
0
26
1d
SwiftData query returns "private" string in WidgetExtension
Hello, I am trying to set up Widgets in my app. I want to fetch my data in the SwiftData container that is shared between my app and my WidgetExtension with App Group. let modelContext = ModelContext(modelContainer) let predicate = #Predicate<Test>{ return $0.attribute == true } return try modelContext.fetch(FetchDescriptor (predicate: predicate, sortBy: [SortDescriptor(\Test.name)])) When this code is run in my WidgetExtension, returned objects attributes values are replaced with "" string. In the logs, Swift Data writes Query returned unrequested identifiers that have been dropped: <private> Any idea what I might be doing wrong to share my SwiftData between my App and my Widget? App Groups capability has been added to both apps and extension with the same identifier. Thank you
2
0
98
5d
SwiftData Decimal loses precision after save/fetch with a minimal reproduction
I believe I may have found a SwiftData persistence bug, but I'd like to verify that I'm not overlooking a documented limitation before filing Feedback. This minimal example appears to lose precision when persisting a Decimal: import Foundation import SwiftData @Model class Item { var value: Decimal init(_ value: Decimal) { self.value = value } } let original = Decimal(string: "123456789012345.6")! let container = try ModelContainer( for: Item.self, configurations: .init(isStoredInMemoryOnly: true) ) let context = ModelContext(container) context.insert(Item(original)) try context.save() let fetched = try ModelContext(container) .fetch(FetchDescriptor<Item>()) .first! print(original) print(fetched.value) Output: 123456789012345.6 123456789012346 A few observations from additional testing: Decimal(string:) preserves the value before persistence. Decimal ↔ NSDecimalNumber bridging preserves the value in separate tests. The value remains exact after model initialization, insertion, and save() on the registered object. The first Swift-visible precision loss appears after fetching from a new ModelContext. As a control, I repeated the test using Core Data with an NSInMemoryStoreType store and an NSDecimalAttributeType attribute. That round-tripped the tested values exactly. Inspecting the SQLite store generated by SwiftData showed the affected value stored as a REAL. At this point it appears the precision loss occurs somewhere in the SwiftData/Core Data persistence pipeline rather than in Decimal itself. Can anyone reproduce this, or is there a documented limitation on Decimal persistence in SwiftData that I have missed? If this is expected behavior, what is the recommended way to persist exact decimal values for financial applications?
0
0
102
6d
SwiftData Decimal loses precision after save/fetch with a minimal reproduction
I believe I may have found a SwiftData persistence bug, but I'd like to verify that I'm not overlooking a documented limitation before filing Feedback. This minimal example appears to lose precision when persisting a Decimal: import Foundation import SwiftData @Model class Item { var value: Decimal init(_ value: Decimal) { self.value = value } } let original = Decimal(string: "123456789012345.6")! let container = try ModelContainer( for: Item.self, configurations: .init(isStoredInMemoryOnly: true) ) let context = ModelContext(container) context.insert(Item(original)) try context.save() let fetched = try ModelContext(container) .fetch(FetchDescriptor<Item>()) .first! print(original) print(fetched.value) Output: 123456789012345.6 123456789012346 A few observations from additional testing: Decimal(string:) preserves the value before persistence. Decimal ↔ NSDecimalNumber bridging preserves the value in separate tests. The value remains exact after model initialization, insertion, and save() on the registered object. The first Swift-visible precision loss appears after fetching from a new ModelContext. As a control, I repeated the test using Core Data with an NSInMemoryStoreType store and an NSDecimalAttributeType attribute. That round-tripped the tested values exactly. Inspecting the SQLite store generated by SwiftData showed the affected value stored as a REAL. At this point it appears the precision loss occurs somewhere in the SwiftData/Core Data persistence pipeline rather than in Decimal itself. Can anyone reproduce this, or is there a documented limitation on Decimal persistence in SwiftData that I have missed? If this is expected behavior, what is the recommended way to persist exact decimal values for financial applications?
0
0
91
6d
SwiftData Model didset
Hi, I'm trying out new SwiftData in a small Xcode project. It seems that the property observers didSet and willSet don't work anymore for swift data anymore. In code like this, the didSet does nothing and seems to never be called. @Model public final class importConfig: Identifiable, ObservableObject{ @Attribute(.unique) public var id: UUID /// Name of the configuration var configName: String /// Numbers App document to open var numbersFilePath: URL? /// Indicate wether current <numbersFilePath> Numbers App document has been loaded and analyzed var isLoaded: Bool = false /// Current selected sheet var selectedSheetID: UUID? { didSet { selectedSheetID = nil print("test") } } } Am I doing something wrong or is it the expected behavior ? If it is the expected behavior, how can I add "business" rules when setting/unsetting value to model properties ? I tried to add rules directly with .onchange() in my views, but this way I have to repeat the same rules/code. Is there any alternative to do so ? Thank you
3
1
1.9k
1w
Best practice for centralizing SwiftData query logic and actions in an @Observable manager?
I'm building a SwiftUI app with SwiftData and want to centralize both query logic and related actions in a manager class. For example, let's say I have a reading app where I need to track the currently reading book across multiple views. What I want to achieve: @Observable class ReadingManager { let modelContext: ModelContext // Ideally, I'd love to do this: @Query(filter: #Predicate<Book> { $0.isCurrentlyReading }) var currentBooks: [Book] // ❌ But @Query doesn't work here var currentBook: Book? { currentBooks.first } func startReading(_ book: Book) { // Stop current book if any if let current = currentBook { current.isCurrentlyReading = false } book.isCurrentlyReading = true try? modelContext.save() } func stopReading() { currentBook?.isCurrentlyReading = false try? modelContext.save() } } // Then use it cleanly in any view: struct BookRow: View { @Environment(ReadingManager.self) var manager let book: Book var body: some View { Text(book.title) Button("Start Reading") { manager.startReading(book) } if manager.currentBook == book { Text("Currently Reading") } } } The problem is @Query only works in SwiftUI views. Without the manager, I'd need to duplicate the same query in every view just to call these common actions. Is there a recommended pattern for this? Or should I just accept query duplication across views as the intended SwiftUI/SwiftData approach?
4
0
1.3k
4w
Prevent SwiftData Upserts
Following the premise that database integrity should be handled by rules in the schema as much as possible, the automatic UPSERT whereby trying to create a record with the same unique key as a record that already exists does not trigger an INSERT error but automatically updates the existing record is pretty alien. I really don't want to enforce this on business logic and I want the backend to do the work. Is there away to prevent the UPSERT?
0
0
404
4w
Under what circumstances does @Query call body?
Hi I was wondering under what circumstances does @Query call body. Does it call it when the result set changes? E.g. object added/removed/moved. Does it also call when the result set is the same but a property of a model changed? I'd prefer 1, since models are @Observable my Views can handle tracking if they need to update when a property of a model changes. But I am concerned it is 2 which would cause unnecessary calls to body? E.g. a ForEach would needlessly be reinit since the model array is exactly the same. So which is it? By the way it would be useful if the docs could be updated with this important info. Thanks
1
0
458
4w
SwiftData, CloudKit and 2 AppleIDs
I have a SwiftData app that runs on iOS, iPadOS, and MacCatalyst and which uses CloudKit for inter-device sync. Unfortunately, I also have two AppleIDs (which I 'll refer to as OLDID and NEWID). Although all three devices (phone, pad and desktop) are currently set up with NEWID as the active AppleID, during development and testing, my desktop Mac used OLDID. Apparently, the system remembers the AppleID to use with each CloudKit app (based on the AppleID active at time of first use), because the desktop app and the mobile apps apparently sync to different AppleID accounts. I can delete the local database on the desktop and delete the local app on the mobile devices and in each case, reloading/rerunning the app causes the respective databases to be restored from the cloud. The two mobile devices sync with each other, but not with the desktop; the desktop doesn't sync with either device. And the two databases have decidedly different contents. My goal is to consolidate everything so that there is one database, shared and synced between desktop, pad, phone and cloud. I presume that there is a setting somewhere (but clearly NOT in the app's sandboxed container) that specifies what iCloud account to use for that (and each) app. Note: I have other apps which sync between all my devices, so the setting must be on a per-app basis. I also presume that if I changed it's value on my desktop (so that all three devices used the same AppleID for cloud services for my app), that the content of the local database on my desktop would be synced automatically to the NEWID cloud account and then (also automatically) synchronized with my mobile devices. I.e., I speculate that I can solve all my problems by changing that setting on my desktop Mac. So I have two questions: Is all this correct? How do I make this setting change. (I.e., where is it and how do I change it) Does anyone have any experience and can help with this issue? Thanks
3
0
509
4w
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 }
5
2
653
Jun ’26
Delay when using ResultsObserver over @Query?
I was testing how to use ResultsObserver on a ViewModel in SwiftData. In Xcode 27, Developer v1, I have the following view import SwiftUI import SwiftData @Model class TaskItem { var name: String var priority: Int init(name: String, priority: Int) { self.name = name self.priority = priority } } @Observable @MainActor class RandomViewModel { let observer: ResultsObserver<TaskItem, Never> @ObservationIgnored private var token: ObservationTracking.Token? var tasks: FetchResultsCollection<TaskItem> { observer.results } init(context: ModelContext) { let descriptor = FetchDescriptor<TaskItem>( sortBy: [SortDescriptor(\.name, order: .reverse)] ) observer = try! ResultsObserver(fetchDescriptor: descriptor, modelContext: context) } } struct RandomView: View { @State var viewModel: RandomViewModel? @Environment(\.modelContext) private var modelContext var body: some View { VStack { if let viewModel { List(viewModel.tasks) { foo in Text(foo.name) } .toolbar { ToolbarItem(placement: .primaryAction) { Button("Add Task") { let task = TaskItem(name: "ZZ New Task \(viewModel.observer.results.count + 1)", priority: 2) print("add \(task.name)") modelContext.insert(task) } } } } else { Text("Hello, World!") } } .task { if viewModel == nil { viewModel = RandomViewModel(context: modelContext) } } } } func testContainer() -> ModelContainer { let schema = Schema([ Item.self, TaskItem.self, ]) let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: true) let container = try! ModelContainer(for: schema, configurations: [modelConfiguration]) let modelContext = container.mainContext for i in 1...20 { let item = TaskItem(name: "Sample Task \(i)", priority: Int.random(in: 1...5)) modelContext.insert(item) } return container } #Preview { NavigationStack { RandomView() } .modelContainer(testContainer()) } When I run the Preview or the simulator, the UI takes a while to actually load and show the results. If I try a version using @Query this doesn't happen import SwiftData import SwiftUI struct RandomQueryView: View { @Environment(\.modelContext) private var modelContext @Query(sort: [SortDescriptor(\TaskItem.name, order: .reverse)]) private var tasks: [TaskItem] var body: some View { List(tasks) { task in Text(task.name) } .toolbar { ToolbarItem(placement: .primaryAction) { Button("Add Task") { let task = TaskItem(name: "ZZ New Task \(tasks.count + 1)", priority: 2) print("add \(task.name)") modelContext.insert(task) } } } } } #Preview { NavigationStack { RandomQueryView() } .modelContainer(testContainer()) } Is this a bug in SwiftData ResultsObserver? or am I using it wrong? I add a recording of my simulator showing the difference
1
0
473
Jun ’26
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
497
Jun ’26
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
555
Jun ’26
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
501
Jun ’26
iOS 18 SwiftData ModelContext reset
Since the iOS 18 and Xcode 16, I've been getting some really strange SwiftData errors when passing @Model classes around. The error I'm seeing is the following: SwiftData/BackingData.swift:409: Fatal error: This model instance was destroyed by calling ModelContext.reset and is no longer usable. PersistentIdentifier(id: SwiftData.PersistentIdentifier.ID(url: x-coredata://34EE9059-A7B5-4484-96A0-D10786AC9FB0/TestApp/p2), implementation: SwiftData.PersistentIdentifierImplementation) The same issue also happens when I try to retrieve a model from the ModelContext using its PersistentIdentifier and try to do anything with it. I have no idea what could be causing this. I'm guessing this is just a bug in the iOS 18 Beta, since I couldn't find a single discussion about this on Google, I figured I'd mention it. if someone has a workaround or something, that would be much appreciated.
17
21
9.7k
Jun ’26
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
567
Jun ’26
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
588
Jun ’26
Best practices
Hi everyone, I'm Alexsander. My friends call me Lexie. I have been working as software developer since 6 years ago, I have a lot of experience with Java and I started working with Angular since the last year. I am new in the Apple ecosystem and I have a question about best practices in full native Swift apps. There is any source (blogs, youtube channels, books, et al.) where I can understand the best practices? Like, I've heard about MVVM to scalable apps but I don't know exactly how to apply it. I think it's because usually I do not have my front-end components in the same project of my backend. I've been watching some videos from Apple Developer youtube channel and they are absolutely amazing, but they only keep teaching people to use the "raw" resources, not matching with the best practices. For example, I saw using swift data we do not need to write any SQL Query, unlike Java Ecossystem where even we use a ORM we usually write our queries natively, whether creating a table or fetching data.
Replies
0
Boosts
0
Views
26
Activity
1d
SwiftData query returns "private" string in WidgetExtension
Hello, I am trying to set up Widgets in my app. I want to fetch my data in the SwiftData container that is shared between my app and my WidgetExtension with App Group. let modelContext = ModelContext(modelContainer) let predicate = #Predicate<Test>{ return $0.attribute == true } return try modelContext.fetch(FetchDescriptor (predicate: predicate, sortBy: [SortDescriptor(\Test.name)])) When this code is run in my WidgetExtension, returned objects attributes values are replaced with "" string. In the logs, Swift Data writes Query returned unrequested identifiers that have been dropped: <private> Any idea what I might be doing wrong to share my SwiftData between my App and my Widget? App Groups capability has been added to both apps and extension with the same identifier. Thank you
Replies
2
Boosts
0
Views
98
Activity
5d
SwiftData Decimal loses precision after save/fetch with a minimal reproduction
I believe I may have found a SwiftData persistence bug, but I'd like to verify that I'm not overlooking a documented limitation before filing Feedback. This minimal example appears to lose precision when persisting a Decimal: import Foundation import SwiftData @Model class Item { var value: Decimal init(_ value: Decimal) { self.value = value } } let original = Decimal(string: "123456789012345.6")! let container = try ModelContainer( for: Item.self, configurations: .init(isStoredInMemoryOnly: true) ) let context = ModelContext(container) context.insert(Item(original)) try context.save() let fetched = try ModelContext(container) .fetch(FetchDescriptor<Item>()) .first! print(original) print(fetched.value) Output: 123456789012345.6 123456789012346 A few observations from additional testing: Decimal(string:) preserves the value before persistence. Decimal ↔ NSDecimalNumber bridging preserves the value in separate tests. The value remains exact after model initialization, insertion, and save() on the registered object. The first Swift-visible precision loss appears after fetching from a new ModelContext. As a control, I repeated the test using Core Data with an NSInMemoryStoreType store and an NSDecimalAttributeType attribute. That round-tripped the tested values exactly. Inspecting the SQLite store generated by SwiftData showed the affected value stored as a REAL. At this point it appears the precision loss occurs somewhere in the SwiftData/Core Data persistence pipeline rather than in Decimal itself. Can anyone reproduce this, or is there a documented limitation on Decimal persistence in SwiftData that I have missed? If this is expected behavior, what is the recommended way to persist exact decimal values for financial applications?
Replies
0
Boosts
0
Views
102
Activity
6d
SwiftData Decimal loses precision after save/fetch with a minimal reproduction
I believe I may have found a SwiftData persistence bug, but I'd like to verify that I'm not overlooking a documented limitation before filing Feedback. This minimal example appears to lose precision when persisting a Decimal: import Foundation import SwiftData @Model class Item { var value: Decimal init(_ value: Decimal) { self.value = value } } let original = Decimal(string: "123456789012345.6")! let container = try ModelContainer( for: Item.self, configurations: .init(isStoredInMemoryOnly: true) ) let context = ModelContext(container) context.insert(Item(original)) try context.save() let fetched = try ModelContext(container) .fetch(FetchDescriptor<Item>()) .first! print(original) print(fetched.value) Output: 123456789012345.6 123456789012346 A few observations from additional testing: Decimal(string:) preserves the value before persistence. Decimal ↔ NSDecimalNumber bridging preserves the value in separate tests. The value remains exact after model initialization, insertion, and save() on the registered object. The first Swift-visible precision loss appears after fetching from a new ModelContext. As a control, I repeated the test using Core Data with an NSInMemoryStoreType store and an NSDecimalAttributeType attribute. That round-tripped the tested values exactly. Inspecting the SQLite store generated by SwiftData showed the affected value stored as a REAL. At this point it appears the precision loss occurs somewhere in the SwiftData/Core Data persistence pipeline rather than in Decimal itself. Can anyone reproduce this, or is there a documented limitation on Decimal persistence in SwiftData that I have missed? If this is expected behavior, what is the recommended way to persist exact decimal values for financial applications?
Replies
0
Boosts
0
Views
91
Activity
6d
SwiftData Model didset
Hi, I'm trying out new SwiftData in a small Xcode project. It seems that the property observers didSet and willSet don't work anymore for swift data anymore. In code like this, the didSet does nothing and seems to never be called. @Model public final class importConfig: Identifiable, ObservableObject{ @Attribute(.unique) public var id: UUID /// Name of the configuration var configName: String /// Numbers App document to open var numbersFilePath: URL? /// Indicate wether current <numbersFilePath> Numbers App document has been loaded and analyzed var isLoaded: Bool = false /// Current selected sheet var selectedSheetID: UUID? { didSet { selectedSheetID = nil print("test") } } } Am I doing something wrong or is it the expected behavior ? If it is the expected behavior, how can I add "business" rules when setting/unsetting value to model properties ? I tried to add rules directly with .onchange() in my views, but this way I have to repeat the same rules/code. Is there any alternative to do so ? Thank you
Replies
3
Boosts
1
Views
1.9k
Activity
1w
Nedd help
Hy my name is max i would need help lurning i‘m trying to get developer mods to make apps
Replies
0
Boosts
0
Views
362
Activity
3w
Best practice for centralizing SwiftData query logic and actions in an @Observable manager?
I'm building a SwiftUI app with SwiftData and want to centralize both query logic and related actions in a manager class. For example, let's say I have a reading app where I need to track the currently reading book across multiple views. What I want to achieve: @Observable class ReadingManager { let modelContext: ModelContext // Ideally, I'd love to do this: @Query(filter: #Predicate<Book> { $0.isCurrentlyReading }) var currentBooks: [Book] // ❌ But @Query doesn't work here var currentBook: Book? { currentBooks.first } func startReading(_ book: Book) { // Stop current book if any if let current = currentBook { current.isCurrentlyReading = false } book.isCurrentlyReading = true try? modelContext.save() } func stopReading() { currentBook?.isCurrentlyReading = false try? modelContext.save() } } // Then use it cleanly in any view: struct BookRow: View { @Environment(ReadingManager.self) var manager let book: Book var body: some View { Text(book.title) Button("Start Reading") { manager.startReading(book) } if manager.currentBook == book { Text("Currently Reading") } } } The problem is @Query only works in SwiftUI views. Without the manager, I'd need to duplicate the same query in every view just to call these common actions. Is there a recommended pattern for this? Or should I just accept query duplication across views as the intended SwiftUI/SwiftData approach?
Replies
4
Boosts
0
Views
1.3k
Activity
4w
Prevent SwiftData Upserts
Following the premise that database integrity should be handled by rules in the schema as much as possible, the automatic UPSERT whereby trying to create a record with the same unique key as a record that already exists does not trigger an INSERT error but automatically updates the existing record is pretty alien. I really don't want to enforce this on business logic and I want the backend to do the work. Is there away to prevent the UPSERT?
Replies
0
Boosts
0
Views
404
Activity
4w
Under what circumstances does @Query call body?
Hi I was wondering under what circumstances does @Query call body. Does it call it when the result set changes? E.g. object added/removed/moved. Does it also call when the result set is the same but a property of a model changed? I'd prefer 1, since models are @Observable my Views can handle tracking if they need to update when a property of a model changes. But I am concerned it is 2 which would cause unnecessary calls to body? E.g. a ForEach would needlessly be reinit since the model array is exactly the same. So which is it? By the way it would be useful if the docs could be updated with this important info. Thanks
Replies
1
Boosts
0
Views
458
Activity
4w
SwiftData, CloudKit and 2 AppleIDs
I have a SwiftData app that runs on iOS, iPadOS, and MacCatalyst and which uses CloudKit for inter-device sync. Unfortunately, I also have two AppleIDs (which I 'll refer to as OLDID and NEWID). Although all three devices (phone, pad and desktop) are currently set up with NEWID as the active AppleID, during development and testing, my desktop Mac used OLDID. Apparently, the system remembers the AppleID to use with each CloudKit app (based on the AppleID active at time of first use), because the desktop app and the mobile apps apparently sync to different AppleID accounts. I can delete the local database on the desktop and delete the local app on the mobile devices and in each case, reloading/rerunning the app causes the respective databases to be restored from the cloud. The two mobile devices sync with each other, but not with the desktop; the desktop doesn't sync with either device. And the two databases have decidedly different contents. My goal is to consolidate everything so that there is one database, shared and synced between desktop, pad, phone and cloud. I presume that there is a setting somewhere (but clearly NOT in the app's sandboxed container) that specifies what iCloud account to use for that (and each) app. Note: I have other apps which sync between all my devices, so the setting must be on a per-app basis. I also presume that if I changed it's value on my desktop (so that all three devices used the same AppleID for cloud services for my app), that the content of the local database on my desktop would be synced automatically to the NEWID cloud account and then (also automatically) synchronized with my mobile devices. I.e., I speculate that I can solve all my problems by changing that setting on my desktop Mac. So I have two questions: Is all this correct? How do I make this setting change. (I.e., where is it and how do I change it) Does anyone have any experience and can help with this issue? Thanks
Replies
3
Boosts
0
Views
509
Activity
4w
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
5
Boosts
2
Views
653
Activity
Jun ’26
Delay when using ResultsObserver over @Query?
I was testing how to use ResultsObserver on a ViewModel in SwiftData. In Xcode 27, Developer v1, I have the following view import SwiftUI import SwiftData @Model class TaskItem { var name: String var priority: Int init(name: String, priority: Int) { self.name = name self.priority = priority } } @Observable @MainActor class RandomViewModel { let observer: ResultsObserver<TaskItem, Never> @ObservationIgnored private var token: ObservationTracking.Token? var tasks: FetchResultsCollection<TaskItem> { observer.results } init(context: ModelContext) { let descriptor = FetchDescriptor<TaskItem>( sortBy: [SortDescriptor(\.name, order: .reverse)] ) observer = try! ResultsObserver(fetchDescriptor: descriptor, modelContext: context) } } struct RandomView: View { @State var viewModel: RandomViewModel? @Environment(\.modelContext) private var modelContext var body: some View { VStack { if let viewModel { List(viewModel.tasks) { foo in Text(foo.name) } .toolbar { ToolbarItem(placement: .primaryAction) { Button("Add Task") { let task = TaskItem(name: "ZZ New Task \(viewModel.observer.results.count + 1)", priority: 2) print("add \(task.name)") modelContext.insert(task) } } } } else { Text("Hello, World!") } } .task { if viewModel == nil { viewModel = RandomViewModel(context: modelContext) } } } } func testContainer() -> ModelContainer { let schema = Schema([ Item.self, TaskItem.self, ]) let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: true) let container = try! ModelContainer(for: schema, configurations: [modelConfiguration]) let modelContext = container.mainContext for i in 1...20 { let item = TaskItem(name: "Sample Task \(i)", priority: Int.random(in: 1...5)) modelContext.insert(item) } return container } #Preview { NavigationStack { RandomView() } .modelContainer(testContainer()) } When I run the Preview or the simulator, the UI takes a while to actually load and show the results. If I try a version using @Query this doesn't happen import SwiftData import SwiftUI struct RandomQueryView: View { @Environment(\.modelContext) private var modelContext @Query(sort: [SortDescriptor(\TaskItem.name, order: .reverse)]) private var tasks: [TaskItem] var body: some View { List(tasks) { task in Text(task.name) } .toolbar { ToolbarItem(placement: .primaryAction) { Button("Add Task") { let task = TaskItem(name: "ZZ New Task \(tasks.count + 1)", priority: 2) print("add \(task.name)") modelContext.insert(task) } } } } } #Preview { NavigationStack { RandomQueryView() } .modelContainer(testContainer()) } Is this a bug in SwiftData ResultsObserver? or am I using it wrong? I add a recording of my simulator showing the difference
Replies
1
Boosts
0
Views
473
Activity
Jun ’26
CloudKit Swiftdata Support for Public Databases
There’s hundreds of forms of people wanting and waiting for swifitdata support for CloudKit public or shared databases. Is this ever going to come or should I just give up and use my own database dont really want to learn core data for such a small part of my app
Replies
0
Boosts
1
Views
467
Activity
Jun ’26
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
497
Activity
Jun ’26
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
555
Activity
Jun ’26
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
501
Activity
Jun ’26
iOS 18 SwiftData ModelContext reset
Since the iOS 18 and Xcode 16, I've been getting some really strange SwiftData errors when passing @Model classes around. The error I'm seeing is the following: SwiftData/BackingData.swift:409: Fatal error: This model instance was destroyed by calling ModelContext.reset and is no longer usable. PersistentIdentifier(id: SwiftData.PersistentIdentifier.ID(url: x-coredata://34EE9059-A7B5-4484-96A0-D10786AC9FB0/TestApp/p2), implementation: SwiftData.PersistentIdentifierImplementation) The same issue also happens when I try to retrieve a model from the ModelContext using its PersistentIdentifier and try to do anything with it. I have no idea what could be causing this. I'm guessing this is just a bug in the iOS 18 Beta, since I couldn't find a single discussion about this on Google, I figured I'd mention it. if someone has a workaround or something, that would be much appreciated.
Replies
17
Boosts
21
Views
9.7k
Activity
Jun ’26
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
567
Activity
Jun ’26
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
588
Activity
Jun ’26
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
548
Activity
Jun ’26