SwiftData

RSS for tag

SwiftData is an all-new framework for managing data within your apps. Models are described using regular Swift code, without the need for custom editors.

Posts under SwiftData tag

200 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

SwiftData Query not updating after data is loaded from iCloud on initial launch
Apparently the @Query property wrapper from SwiftData does not update when data is loaded from CloudKit. The data can be programmatically be accessed but nothing appears in the view. Steps to reproduce: Create new Xcode project using the SwiftData storage option. Provide a default value for the Item Model. That is required so data can be automatically synced by SwiftData. Enable iCloud -> CloudKit capabilities and choose a container Enable Background Modes -> Remote notification capability Add a toolbar button that prints the number of items from @Query like this: ToolbarItem { Button { print(items.count) } label: { Label("Count", systemImage: "1.circle") } } Install app on a physical device that can sync to iCloud. Add some items using the + in the toolbar Delete app and wait for around a minute Reinstall app with a debugger attached Press the 1.circle button in the toolbar. It will print either 0 or the number of items you previously added. When it does not print 0 the data should be visible but it is not. Once you quit and relaunch the app or press the + button again, all of the items appear. Has anyone else experienced this before? Anything I can do so the data appears / the view reloads once the items are available? I need to update my view once the data has been loaded from iCloud. I already filed a bug report with id FB14619787.
1
2
754
Aug ’24
SwiftData relation not update UI
The 1 to 1 relation models: @Model class Country { var name: String var population: Population? init(name: String, population: Population? = nil) { self.name = name self.population = population } } @Model class Population { var country: Country? var count: Int init(country: Country? = nil, count: Int) { self.country = country self.count = count } } I don't know why not update the UI when click population label. But if I expand the CountryDetail it will works. struct DemoView: View { @Query var countries: [Country] @Environment(\.modelContext) private var context var body: some View { NavigationStack { List { ForEach(countries) { country in VStack(alignment: .leading) { Text(country.name) if let population = country.population { // bug: not update CountryDetail(population: population) // like above but expanded, it is ok Text("population: \(population.count)") .onTapGesture { Task.detached { try await DemoData(modelContainer: DemoData.sharedContainer).changePopulation() } } } } } }.safeAreaInset(edge: .bottom) { Button("Add") { let country = Country(name: "US") context.insert(country) let population = Population(country: country, count: 0) country.population = population } } } } } struct CountryDetail: View { @Bindable var population: Population var body: some View { Text("population: \(population.count)") .onTapGesture { Task.detached { try await DemoData(modelContainer: DemoData.sharedContainer).changePopulation() } } } } @ModelActor actor DemoData { static let sharedContainer = try! ModelContainer(for: Country.self, configurations: .init(isStoredInMemoryOnly: true)) func changePopulation() throws { let descriptor = FetchDescriptor<Population>() let all = try modelContext.fetch(descriptor).first if let population = try modelContext.fetch(descriptor).first { population.count += 1 try modelContext.save() print("population count", population.count) } else { fatalError("not found population") } } }
2
0
304
Aug ’24
SwiftData Tables disappearing while test my app!
I begin testing my IOS swiftdats Xcode 15 swift 5 on Sonoma and I am able to create my siwftdata tables as well as add records to several of the tables, Then as I proceeded with my te tables disappear and I get this error in the Xcode debug console: error: Error: Persistent History (6) has to be truncated due to the following entities being removed: ( AppSettings, Invoice, Clientele, Pay, InvoiceItem, TrackingArt ) This app used to work fine and as I was making changes it started behaving in this manner. Beside the code I will supply the entire debug console with the attached file debugConsole.txt Here is how I have the swift data containers setup. import SwiftData import TipKit import CloudKit @main struct ArtManagerApp: App { @StateObject private var copyInvoiceDetails = CopyInvoiceDetails() @StateObject private var copyPaymentDetails = CopyPaymentDetails() @StateObject private var artTypeSettings = ArtTypeSettings() @StateObject private var tipManager = TipManager() // @Query(sort: \ArtPiece.artPieceID, order: .forward) private var artPieces: [ArtPiece] // @Query(sort: \AppSettings.setID, order: .reverse) private var settingsList: [AppSettings] var sharedModelContainer: ModelContainer = { let schema = Schema([ ArtPiece.self, Clientele.self, TrackingArt.self, Invoice.self, InvoiceItem.self, AppSettings.self, Pay.self ]) let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false) do { return try ModelContainer(for: schema, configurations: [modelConfiguration]) } catch { fatalError("Could not create ModelContainer: \(error)") } }() var body: some Scene { WindowGroup { ContentView() .navigationTitle("🎨 Art Manager") .environmentObject(artTypeSettings) .environmentObject(copyInvoiceDetails) .environmentObject(copyPaymentDetails) .environmentObject(tipManager) // Pass it to the ContentView .modelContainer(sharedModelContainer) } } } class TipManager: ObservableObject { @Published var tips: [ArtManagerTip] = [] init() { loadTips() } func loadTips() { tips = [ArtManagerTips.search_tip, ArtManagerTips.delete_tip, ArtManagerTips.extendedSearch_tip, ArtManagerTips.searchPayments_tip, ArtManagerTips.searchArt_tip, ArtManagerTips.librarySearch_tip, ArtManagerTips.artMaintenanceSearch_tip] } } class CopyPaymentDetails: ObservableObject { @Published var payNumber: Int32 = 0 @Published var payType: String = "" @Published var payPatronID: Int32 = 0 @Published var payPatronName: String = "" @Published var payPatronAddress: String = "" @Published var payPaymentAmount: Double = 0.0 @Published var payDatePayed: Date = Date() } class CopyInvoiceDetails: ObservableObject { @Published var invoiceNumber: Int32 = 0 @Published var invoicePatronName: String = "" @Published var invoicePatronPO: String = "" @Published var invoiceDateCreated: Date = Date() @Published var artPieceIDSaved: [Int32] = [] }
7
0
682
Aug ’24
SwiftData saying CoreData: error: Failed to stat path
This just started happening when installing my app on my phone and ipad. It still seems to work and the errors go away on the second installation, but it doesn't strike me as good. The app has not been released yet. When I remove the AppGroup, the error disappears. But I have a widget, so I need the AppGroup. I've cleaned the build, deleted derived files, and rebooted many times. I've deleted the app on the device and rebooted the device many times. I've deleted the AppGroup in iCloud and then recreated it. I was really hoping that would work, but nope. I've created a new App Group and that didn't make a difference either. So I'm stumped. Any thoughts on how to fix this? thanks CoreData: error: Failed to stat path '/private/var/mobile/Containers/Shared/AppGroup/2602E28B-089C-4011-BA09-19D11183E4F7/Library/Application Support/default.store', errno 2 / No such file or directory. CoreData: error: Executing as effective user 501 CoreData: error: Failed to statfs file; errno 2 / No such file or directory. CoreData: error: Logging status information for directory path: /private/var/mobile/Containers/Shared/AppGroup/2602E28B-089C-4011-BA09-19D11183E4F7/Library/Application Support CoreData: error: Executing as effective user 501 .... error: URL: file:///private/var/mobile/Containers/Shared/AppGroup/2602E28B-089C-4011-BA09-19D11183E4F7/Library/Application%20Support/default.store error: <NSPersistentStoreCoordinator: 0x300a3e610>: Attempting recovery from error encountered during addPersistentStore: 0x302f5f510 Error Domain=NSCocoaErrorDomain Code=512 "The file couldn’t be saved." UserInfo={reason=Failed to create file; code = 2} error: During recovery, parent directory path reported as missing error: Recovery attempt while adding <NSPersistentStoreDescription: 0x302f5f510> (type: SQLite, url: file:///private/var/mobile/Containers/Shared/AppGroup/2602E28B-089C-4011-BA09-19D11183E4F7/Library/Application%20Support/default.store) was successful!
1
0
575
Aug ’24
SwiftData ModelContext fails to delete all model instances from unit tests.
Hi! I'm running into some confusing behavior when attempting to delete all instance of one model type from a ModelContext. My problem is specifically using the delete(model:where:includeSubclasses:)^1 function (and passing in a model type). I seem to be running into situations where this function fails silently without throwing an error (no models are deleted). I am seeing this same behavior from Xcode_15.4.0 and Xcode_16_beta_4. I start with a model: @Model final public class Item { var timestamp: Date public init(timestamp: Date = .now) { self.timestamp = timestamp } } Here is an example of a Store class that wraps a ModelContext: final public class Store { public let modelContext: ModelContext public init(modelContainer: SwiftData.ModelContainer) { self.modelContext = ModelContext(modelContainer) } } extension Store { private convenience init( schema: Schema, configuration: ModelConfiguration ) throws { let container = try ModelContainer( for: schema, configurations: configuration ) self.init(modelContainer: container) } } extension Store { public convenience init(url: URL) throws { let schema = Schema(Self.models) let configuration = ModelConfiguration(url: url) try self.init( schema: schema, configuration: configuration ) } } extension Store { public convenience init(isStoredInMemoryOnly: Bool = false) throws { let schema = Schema(Self.models) let configuration = ModelConfiguration(isStoredInMemoryOnly: isStoredInMemoryOnly) try self.init( schema: schema, configuration: configuration ) } } extension Store { public func fetch<T>(_ type: T.Type) throws -> Array<T> where T : PersistentModel { try self.modelContext.fetch( FetchDescriptor<T>() ) } } extension Store { public func fetchCount<T>(_ type: T.Type) throws -> Int where T : PersistentModel { try self.modelContext.fetchCount( FetchDescriptor<T>() ) } } extension Store { public func insert<T>(_ model: T) where T : PersistentModel { self.modelContext.insert(model) } } extension Store { public func delete<T>(model: T.Type) throws where T : PersistentModel { try self.modelContext.delete(model: model) } } extension Store { public func deleteWithIteration<T>(model: T.Type) throws where T : PersistentModel { for model in try self.fetch(model) { self.modelContext.delete(model) } } } extension Store { private static var models: Array<any PersistentModel.Type> { [Item.self] } } That should be pretty simple… I can use this Store to read and write Item instances to a ModelContext. Here is an example of an executable that shows off the unexpected behavior: func main() async throws { do { let store = try Store(isStoredInMemoryOnly: true) store.insert(Item()) print(try store.fetchCount(Item.self) == 1) try store.delete(model: Item.self) print(try store.fetchCount(Item.self) == 0) } do { let store = try Store(isStoredInMemoryOnly: true) store.insert(Item()) print(try store.fetchCount(Item.self) == 1) try store.deleteWithIteration(model: Item.self) print(try store.fetchCount(Item.self) == 0) } do { let store = try StoreActor(isStoredInMemoryOnly: true) await store.insert(Item()) print(try await store.fetchCount(Item.self) == 1) try await store.delete(model: Item.self) print(try await store.fetchCount(Item.self) == 0) } do { let store = try StoreActor(isStoredInMemoryOnly: true) await store.insert(Item()) print(try await store.fetchCount(Item.self) == 1) try await store.deleteWithIteration(model: Item.self) print(try await store.fetchCount(Item.self) == 0) } } try await main() My first step is to set up an executable with an info.plist to support SwiftData.^2 My expectation is all these print statements should be true. What actually happens is that the calls to delete(model:where:includeSubclasses:) seem to not be deleting any models (and also seem to not be throwing errors). I also have the option to test this behavior with XCTest. I see the same unexpected behavior: import XCTest final class StoreXCTests : XCTestCase { func testDelete() throws { let store = try Store(isStoredInMemoryOnly: true) store.insert(Item()) XCTAssert(try store.fetchCount(Item.self) == 1) try store.delete(model: Item.self) XCTAssert(try store.fetchCount(Item.self) == 0) } func testDeleteWithIteration() throws { let store = try Store(isStoredInMemoryOnly: true) store.insert(Item()) XCTAssert(try store.fetchCount(Item.self) == 1) try store.deleteWithIteration(model: Item.self) XCTAssert(try store.fetchCount(Item.self) == 0) } } Those tests fail… implying that the delete(model:where:includeSubclasses:) is not actually deleting any models. FWIW… I see the same behavior (from command-line and XCTest) when my Store conforms to ModelActor.^3 ^4 This does not seem to be the behavior I am seeing from using the delete(model:where:includeSubclasses:) in a SwiftUI app.^5 Calling the delete(model:where:includeSubclasses:) function from SwiftUI does delete all the model instances. The SwiftUI app uses a ModelContext directly (without a Store type). I can trying writing unit tests directly against ModelContext and I see the same behavior as before (no model instances are being deleted).^6 Any ideas about that? Is this a known issue with SwiftData that is being tracked? Is the delete(model:where:includeSubclasses:) known to be "flaky" when called from outside SwiftUI? Is there anything about the way these ModelContext instance are being created that we think is leading to this unexpected behavior?
5
0
766
Aug ’24
SwiftData Model fails to build from Xcode 15.4 when class access control is package?
Hi! I'm building an app from production Xcode_15.4.0 and I'm seeing strange behavior from the Model macro: import SwiftData @Model package class Person { init() { } } Building this from Xcode_15.4.0 or Swift 5.10 leads to these errors: /var/folders/1j/0r1s_v0n4bn200kt9nkm9j5w0000gn/T/swift-generated-sources/@__swiftmacro_9MyLibrary6Person5ModelfMe_.swift:1:1: error: initializer 'init(backingData:)' must be as accessible as its enclosing type because it matches a requirement in protocol 'PersistentModel' extension Person: SwiftData.PersistentModel { ^ /Users/rick/Desktop/MyLibrary/Sources/MyLibrary/MyLibrary.swift:3:1: note: in expansion of macro 'Model' on class 'Person' here @Model package class Person { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /var/folders/1j/0r1s_v0n4bn200kt9nkm9j5w0000gn/T/swift-generated-sources/@__swiftmacro_9MyLibrary6Person5ModelfMm_.swift:19:10: note: mark the initializer as 'package' to satisfy the requirement required init(backingData: any SwiftData.BackingData<Person>) { ^ /Users/rick/Desktop/MyLibrary/Sources/MyLibrary/MyLibrary.swift:3:1: note: in expansion of macro 'Model' on class 'Person' here @Model package class Person { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /var/folders/1j/0r1s_v0n4bn200kt9nkm9j5w0000gn/T/swift-generated-sources/@__swiftmacro_9MyLibrary6Person5ModelfMe_.swift:1:1: error: property 'schemaMetadata' must be as accessible as its enclosing type because it matches a requirement in protocol 'PersistentModel' extension Person: SwiftData.PersistentModel { ^ /Users/rick/Desktop/MyLibrary/Sources/MyLibrary/MyLibrary.swift:3:1: note: in expansion of macro 'Model' on class 'Person' here @Model package class Person { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /var/folders/1j/0r1s_v0n4bn200kt9nkm9j5w0000gn/T/swift-generated-sources/@__swiftmacro_9MyLibrary6Person5ModelfMm_.swift:13:12: note: mark the static property as 'package' to satisfy the requirement static var schemaMetadata: [SwiftData.Schema.PropertyMetadata] { ^ /Users/rick/Desktop/MyLibrary/Sources/MyLibrary/MyLibrary.swift:3:1: note: in expansion of macro 'Model' on class 'Person' here @Model package class Person { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /var/folders/1j/0r1s_v0n4bn200kt9nkm9j5w0000gn/T/swift-generated-sources/@__swiftmacro_9MyLibrary6Person5ModelfMe_.swift:1:1: error: initializer 'init(backingData:)' must be as accessible as its enclosing type because it matches a requirement in protocol 'PersistentModel' extension Person: SwiftData.PersistentModel { ^ /Users/rick/Desktop/MyLibrary/Sources/MyLibrary/MyLibrary.swift:3:1: note: in expansion of macro 'Model' on class 'Person' here @Model package class Person { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /var/folders/1j/0r1s_v0n4bn200kt9nkm9j5w0000gn/T/swift-generated-sources/@__swiftmacro_9MyLibrary6Person5ModelfMm_.swift:19:10: note: mark the initializer as 'package' to satisfy the requirement required init(backingData: any SwiftData.BackingData<Person>) { ^ /Users/rick/Desktop/MyLibrary/Sources/MyLibrary/MyLibrary.swift:3:1: note: in expansion of macro 'Model' on class 'Person' here @Model package class Person { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /var/folders/1j/0r1s_v0n4bn200kt9nkm9j5w0000gn/T/swift-generated-sources/@__swiftmacro_9MyLibrary6Person5ModelfMe_.swift:1:1: error: property 'schemaMetadata' must be as accessible as its enclosing type because it matches a requirement in protocol 'PersistentModel' extension Person: SwiftData.PersistentModel { ^ /Users/rick/Desktop/MyLibrary/Sources/MyLibrary/MyLibrary.swift:3:1: note: in expansion of macro 'Model' on class 'Person' here @Model package class Person { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /var/folders/1j/0r1s_v0n4bn200kt9nkm9j5w0000gn/T/swift-generated-sources/@__swiftmacro_9MyLibrary6Person5ModelfMm_.swift:13:12: note: mark the static property as 'package' to satisfy the requirement static var schemaMetadata: [SwiftData.Schema.PropertyMetadata] { ^ /Users/rick/Desktop/MyLibrary/Sources/MyLibrary/MyLibrary.swift:3:1: note: in expansion of macro 'Model' on class 'Person' here @Model package class Person { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: fatalError Building from Xcode_16_beta_4 or Swift 6.0 builds with no errors. Is this package issue being tracked for SwiftData when building from 5.10? It looks like this is fixed from 6.0… but I would like to build this code from production Swift today. Potential workarounds: Mark the class as internal or public? Use Xcode to inline the macro expansion and directly modify the broken functions with the correct access control? Any more ideas? My preference would be to keep this type package (while also building from 5.10). Any more workarounds (other than expanding the macro and modifying the functions myself by-hand)? Thanks!
0
0
212
Jul ’24
SwiftData: Unable to find a configuration named 'default' in the specified managed object model
I have a SwiftUI + SwiftData (with iCloud) app. The setup code is standard, with schema migrations (mostly lightweight, one custom). Everything works correctly except in one scenario. When I run a newer version of the app (with an updated schema adding one field + migration) on a device with the previous data container (the usual app version update through TestFlight), I encounter an issue on the first launch. The app crashes on the first "cold" start but runs successfully on subsequent launches. The error I receive on the first run is: addPersistentStoreWithType:configuration:URL:options:error: returned error NSCocoaErrorDomain (134060) NSLocalizedFailureReason : Unable to find a configuration named 'default' in the specified managed object model. What might be a problem and how to resolve it?
2
0
457
Aug ’24
SwiftData Relationships
I like knowing what I'm looking at in my code, so I'd like to know explicitly that the SwiftData variable that is the inverse is "decorated" with the @Relationship macro also, so: Can I use the @Relationship macro on the inverse class of a relationship if I don't specify it with .inverse ? IE: From Company @Relationship(deleteRule: .nullify, inverse: \Address.company) var addresses: [Address]? and set the other as: From Address @Relationship var company: Company?
1
0
298
Jul ’24
Does SwiftUI List reuse its cells?
I have a set of SwiftData objects, which include a thumbnail and also HD image data. I also have SwiftUI List, presenting, some information, including thumbnail image. The problem is, firstly, when I scroll, memory goes up and up, never seemingly releasing objects showed once. Secondly, it seems, it loads in the memory the whole object, including HD data, not only thumbnail. What can be the right way to work around here?
2
0
514
Jul ’24
SwiftData updates delay in widget
My SwiftData model doesn't have time to update, and the widget gets old data on the timeline I create simple SwiftData app with widget extension. To share swiftdata between widget and app I use the same approach as in sample code "Adopting SwiftData for a Core Data app": let modelContext = ModelContext(DataModel.shared.modelContainer) if let models = try? modelContext.fetch(fetchDescriptor) { // use } After I create/delete/updated model I call: WidgetCenter.shared.reloadAllTimelines() The problem is that the widget receives outdated data as a result of modelContext.fetch. To get the new data I need to call WidgetCenter.shared.reloadAllTimelines() twice or with some delay: // MyModelEditorView private func save() { if let myModel { myModel.title = title } else { let myModel = MyModel( title: title ) modelContext.insert(word) } WidgetCenter.shared.reloadAllTimelines() // i have to call it twice WidgetCenter.shared.reloadAllTimelines() } I couldn't test SampleCode for similar update behavior, because somehow I couldn't get the models into the widget and I only have "No Trip" displayed there. If I remove the second call, the UI is updated immediately and the new title is displayed, but the widget in the timeline receive the old title. I don't understand whether this is the case and I need to update the widget with a delay or am I doing something wrong? BTW: Why is sample code in init we don't use shared container? private let modelContainer: ModelContainer init() { do { // why we don't use DataModel.shared.modelContainer modelContainer = try ModelContainer(for: Trip.self) } catch { fatalError("Failed to create the model container: \(error)") } }
1
1
362
Jul ’24
SwiftData multiple selection from sidebar
Hello, I am developing a swift data macOS reminders app. I need the user to be able to select multiple items from the sidebar and record a variable of which ones are selected. However, I also want a variable that will track the first one of the selection selected so it can be shown in the detail view. I would like this to be similar to the Apple reminders app, where u can select multiple to delete, but only one list is shown in the detail view. how do I do this? thanks so much, Dev_Pro
0
1
275
Jul ’24
Does SwiftData require paging?
Hello. I'm going to create an app that supports purchase records. SwiftData was used to implement storage, backup, and restoration functions at once. One question is whether paging is necessary. When you receive data from a server, you usually implement paging to send and receive data efficiently. In the case of Realm, I know that it uses Lazy data, so I know that there is no need for paging. What about SwiftData? Can the number of data affect performance??
0
1
311
Jul ’24
Invalid Swift Support
Hi, Can someone please help me with the below issue, I validated the app before distributing from Xcode, and it passed. but I received a mail from Apple Developer Relations saying there a problem, but I don't have any clue how to solve this problem. ITMS-90429: Invalid Swift Support - The files libswiftDarwin.dylib, libswiftDispatch.dylib, libswiftCoreGraphics.dylib, libswiftCoreFoundation.dylib, libswiftUIKit.dylib, libswiftMetal.dylib, libswiftCore.dylib, libswiftFoundation.dylib, libswiftQuartzCore.dylib, libswiftos.dylib, libswiftObjectiveC.dylib, libswiftCoreImage.dylib aren’t at the expected location /Payload/connectdots.app/Frameworks. Move the file to the expected location, rebuild your app using the current public (GM) version of Xcode, and resubmit it. I dont know where these dylibs are now and how to move them. Also I am using Xcode 15.3. what does it mean current public version of Xcode Thanks in Advance, Thirupathi.
1
0
229
Jul ’24
Why does my SwiftUI app crash when opened from an intent?
I'm encountering a crash in my SwiftUI app when it is opened via an AppIntent. The app runs perfectly when launched by tapping the app icon, but it crashes when opened from an intent. Here is a simplified version of my code: import AppIntents import SwiftData import SwiftUI @main struct GOGODemoApp: App { @State private var state: MyController = MyController() var body: some Scene { WindowGroup { MyView() //.environment(state) // ok } .environment(state) // failed to start app, crash with 'Dispatch queue: com.apple.main-thread' } } struct MyView: View { @Environment(MyController.self) var stateController var body: some View { Text("Hello") } } @Observable public class MyController { } struct OpenIntents: AppIntent { static var title: LocalizedStringResource = "OpenIntents" static var description = IntentDescription("Open App from intents.") static var openAppWhenRun: Bool = true @MainActor func perform() async throws -> some IntentResult { return .result() } } Observations: The app works fine when launched by tapping the app icon. The app crashes when opened via an AppIntent. The app works if I inject the environment in MyView instead of in WindowGroup. Question: Why does injecting the environment in WindowGroup cause the app to crash when opened from an intent, but works fine otherwise? What is the difference when injecting the environment directly in MyView?
1
0
423
Aug ’24
SwiftData rollback not updating the UI
I'm building a simple App using SwiftData. In my app a user can create, remove and edit posts. When editing, I want them to be able to hit "Save" to persist the changes or "Cancel" to discard the changes. The approach I'm using is to disable autosave and call modelContext.save() when saving and modelContext.rollback() when discarding the changes. So my modelContainer is defined as follows: WindowGroup { ContentView() .modelContainer(for: [Post.self], isAutosaveEnabled: false) } and I Save and Cancel like this: PostForm(post: post) .toolbar { ToolbarItemGroup(placement: .cancellationAction) { Button("Cancel") { if modelContext.hasChanges { modelContext.rollback() } dismiss() } } ToolbarItemGroup(placement: .confirmationAction) { Button("Save") { do { if modelContext.hasChanges { try modelContext.save() } } catch { fatalError("Failed to save post: \(error.localizedDescription)") } callback?() dismiss() } } } The issue I am facing is that after calling modelContext.rollback() my Posts aren't updating in the UI, they still show the changes. Restarting the app shows the Posts without the changes so I'm guessing that modelContext.rollback() is in fact discarding the changes and not persisting them in the Storage, the UI is the one that is not reacting to the change. Am I doing something wrong here? Is this approach correct?
0
1
315
Jul ’24
Xcode 16 Beta 3: "Cannot expand accessors on variable declared with 'let'"
Running into this new issue in beta 3. All of our immutable model attributes are now triggering swift compiler error from the title (tied to swift 6 - warning in swift 5). Neither warning or error show up on previous builds. Anyone else running into this? Hopefully not a limitation on swiftData that attributes must be mutable? filed as: FB14379932 (new in Xcode 16 beta3: "cannot expand accessors on variable declared with 'let'" in SwiftData Models)
5
4
1.8k
Sep ’24
SwiftData Initial sync on MacOS is partial
Yesterday I bumped into a weird issue. I've got an application that was previously only available on iOS, however I'm now creating a version for MacOS. As I released the "working" application to TestFlight, a friend of mine told me that they don't see any of their data in the mac application. Thus, I started to investigate, and found out that on the Testflight version, the initial sync fails to sync data that didn't exist before the installation. However, in the debug version of the application (directly ran from XCode) the initial sync syncs all data, and after downloading the production version from TestFlight it works like a charm.
0
0
243
Jul ’24
Model Container Sendable Throwing Error in Swift 6
Hi all, I just wanted to ask how people were using ModelActor with the Swift 6 language mode enabled. My current implementation involves passing the ModelContainer to my ModelActor, which worked in Sonoma and previous betas of Sequoia, however in the current Beta 3, I get this error: "Sending 'self.modelContext.container' risks causing data races" I am a bit confused by this, as from what I understand, ModelContainer conforms to Sendable, so ideally this error should not be thrown. Is this a bug in Beta 3? Thanks in advance.
3
1
986
Jul ’24
ModelActors not persisting relationships in iOS 18 beta
I've already submitted this as a bug report to Apple, but I am posting here so others can save themselves some troubleshooting. This is submitted as FB14337982 with an attached complete Xcode project to replicate. In iOS 17 we use a ModelActor to download data which is saved as an Event, and then save it to SwiftData with a relationship to a Location. In iOS 18 22A5307d we are seeing that this code no longer persists the relationship to the Location, but still saves the Event. If we put a breakpoint in that ModelActor we see that the object graph is correct within the ModelActor stack trace at the time we call modelContext.save(). However, after saving, the relationship is missing from the default.store SQLite file, and of course from the app UI. Here is a toy example showing how inserting an Employee into a Company using a ModelActor gives unexpected results in iOS 18 22A5307d but works as expected in iOS 17. It appears that no relationships data survives being saved in a ModelActor.ModelContext. Also note there seems to be a return of the old bug that saving this data in the ModelActor does not update the @Query in the UI in iOS 18 but does so in iOS 17. Models @Model final class Employee { var uuid: UUID = UUID() @Relationship(deleteRule: .nullify) public var company: Company? /// For a concise display @Transient var name: String { self.uuid.uuidString.components(separatedBy: "-").first ?? "NIL" } init(company: Company?) { self.company = company } } @Model final class Company { var uuid: UUID = UUID() @Relationship(deleteRule: .cascade, inverse: \Employee.company) public var employees: [Employee]? = [] /// For a concise display @Transient var name: String { self.uuid.uuidString.components(separatedBy: "-").first ?? "NIL" } init() { } } ModelActor import OSLog private let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "SimpleModelActor") @ModelActor final actor SimpleModelActor { func addEmployeeTo(CompanyWithID companyID: PersistentIdentifier?) { guard let companyID, let company: Company = self[companyID, as: Company.self] else { logger.error("Could not get a company") return } let newEmployee = Employee(company: company) modelContext.insert(newEmployee) logger.notice("Created employee \(newEmployee.name) in Company \(newEmployee.company?.name ?? "NIL")") try! modelContext.save() } } ContentView import OSLog private let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "View") struct ContentView: View { @Environment(\.modelContext) private var modelContext @Query private var companies: [Company] @Query private var employees: [Employee] @State private var simpleModelActor: SimpleModelActor! var body: some View { ScrollView { LazyVStack { DisclosureGroup("Instructions") { Text(""" Instructions: 1. In iOS 17, tap Add in View. Observe that an employee is added with Company matching the shown company name. 2. In iOS 18 beta (22A5307d), tap Add in ModelActor. Note that the View does not update (bug 1). Note in the XCode console that an Employee was created with a relationship to a Company. 3. Open the default.store SQLite file and observe that the created Employee does not have a Company relationship (bug 2). The relationship was not saved. 4. Tap Add in View. The same code is now executed in a Button closure. Note in the XCode console again that an Employee was created with a relationship to a Company. The View now updates showing both the previously created Employee with NIL company, and the View-created employee with the expected company. """) .font(.footnote) } .padding() Section("**Companies**") { ForEach(companies) { company in Text(company.name) } } .padding(.bottom) Section("**Employees**") { ForEach(employees) { employee in Text("Employee \(employee.name) in company \(employee.company?.name ?? "NIL")") } } Button("Add in View") { let newEmployee = Employee(company: companies.first) modelContext.insert(newEmployee) logger.notice("Created employee \(newEmployee.name) in Company \(newEmployee.company?.name ?? "NIL")") try! modelContext.save() } .buttonStyle(.bordered) Button("Add in ModelActor") { Task { await simpleModelActor.addEmployeeTo(CompanyWithID: companies.first?.persistentModelID) } } .buttonStyle(.bordered) } } .onAppear { simpleModelActor = SimpleModelActor(modelContainer: modelContext.container) if companies.isEmpty { let newCompany = Company() modelContext.insert(newCompany) try! modelContext.save() } } } }
8
1
808
Aug ’24
Context.insert() but at index 0
Hello! I am an inexperienced programmer learning swiftUI and swiftData so apologies in advance if this answer can be found elsewhere. I want to display a list of recent transcriptions, stored in modelContainer, in reversed order. I attempted to do transcriptionsList.reversed() in a ForEach (which is in a swiftUI List), but .onDelete gets messed up as it is deleting the items as per the normal order. The question is, is there a way when using context.insert(), that I can specify to insert at index 0? Or is there a better way of resolving this? Thanks in advance! The code when pasted in here appears to not be formatted correctly so I didn't include code
2
0
294
Jul ’24