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

SwiftUI State not reliable updating
Hello, I have a SwiftUI view with the following state variable: @State private var startDate: Date = Date() @State private var endDate: Date = Date() @State private var client: Client? = nil @State private var project: Project? = nil @State private var service: Service? = nil @State private var billable: Bool = false Client, Project, and Service are all SwiftData models. I have some view content that binds to these values, including Pickers for the client/project/service and a DatePicker for the Dates. I have an onAppear listener: .onAppear { switch state.mode { case .editing(let tt): Task { await MainActor.run { startDate = tt.startDate endDate = tt.endDate client = tt.client project = tt.project service = tt.service billable = tt.billable } } default: return } } This works as expected. However, if I remove the Task & MainActor.run, the values do not fully update. The DatePickers show the current date, the Pickers show a new value but tapping on them shows a nil default value. What is also extremely strange is that if tt.billable is true, then the view does update as expected. I am using Xcode 15.4 on iOS simulator 17.5. Any help would be appreciated.
0
0
38
7h
How to properly add data files into a SwiftData ModelDocument file package
Hi all, I am working on a macOS/iOS sandboxed app with SwiftUI/SwiftData. The app saves its' data into a ModelDocument file. But I want to also save large binary data files into this file. I create the DocumentGroup scene with: DocumentGroup(editing: Entry.self, contentType: .myDocument) { MainWindowView() } In my MainWindowView, I use @Environment(\.documentConfiguration) private var documentConfiguration to get the URL to the user created ModelDocument file URL. When I need to add large binary file into the ModelDocument file, I call a method in my model: func saveReferencedData(_ data: Data, documentURL: URL?) throws { let logger = Logger(subsystem: "saveReferencedData", category: "Asset") if let documentURL { let referencedFileName = "\(entryIdentifier)_\(assetIdentifier).\(assetType)" let tempFileURL = documentURL.appending(components: referencedFileName) if documentURL.startAccessingSecurityScopedResource() { do { try data.write(to: tempFileURL, options: []) } catch { documentURL.stopAccessingSecurityScopedResource() throw AssetFileOperationError.unableToSaveReferenceFile } self.referencedFileLocation = referencedFileName logger.debug("Successfully saved image data to: \(referenceFileURL)") } documentURL.stopAccessingSecurityScopedResource() } else { logger.debug("ERROR! Unable to save referenced image file because document URL is nil.") } } When this method is called, the data file is saved, but immediately I gets this diablog box: If I click on any of the options in the dialog box, the binary data file is removed. I think this is a permission problem and I am not writing to the ModelDocument file correctly. But I can not find any information online to experiment more. Does anyone have experience with a customized ModelDocument file with more data files written into it? Or if you have any insight or advice, it would be greatly appreciated. Thank you so much for reading.
0
0
32
14h
When to use structs with swift data?
I am unsure the correct way to model my data. I have a swift data object and then some referenced objects. Is there ever a reason those should just be structs or should they always be swift data objects themselves? for example right now this is what I'm doing: @Model final class Exam { var timestamp: Date @Attribute(.unique) var examID: UUID var title: String var questions: [Question] ... } and Question is struct Question: Codable, Identifiable { var id: UUID var number: Int var points: Int var prompt: String var answer: String } is there any problem with this or should I not be using a Struct for Question and instead use another Swift Data object with @Relationship ? I thought since its a simple object just using a struct would be fine, however... when I create a new Question object, it seems to create SwiftUI retain cycles with the warning === AttributeGraph: cycle detected through attribute 633984 === in the terminal for example, Button("Add Question", systemImage: "questionmark.diamond") { let newQuestion = Question(id: UUID(), number: exam.questions.count+1, points: 1, prompt: "", answer: "", type: .multipleChoice) exam.questions.append(newQuestion) } So, is it ok to mix structs with swift data objects or is it not best practice? And is this causing the SwiftUI retain cycles or are the issues unrelated?
0
0
52
1d
Tokenised text search in SwiftData help
The SwiftData predicate documentation says that it supports the contains(where:) sequence operation in addition to the contains(_:) string comparison but when I put them together in a predicate to try and perform a tokenised search I get a runtime error. Unsupported subquery collection expression type (NSInvalidArgumentException) I need to be able to search for items that contain at least one of the search tokens, this functionality is critical to my app. Any suggestions are appreciated. Also does anyone with experience with CoreData know if this is possible to do in CoreData with NSPredicate? import SwiftData @Model final class Item { var textString: String = "" init() {} } func search(tokens: Set<String>, context: ModelContext) throws -> [Item] { let predicate: Predicate<Item> = #Predicate { item in tokens.contains { token in item.textString.contains(token) } } let descriptor = FetchDescriptor(predicate: predicate) return try context.fetch(descriptor) }
2
1
110
9h
Crash by SwiftData MigarionPlan
I am a develop beginner. Recently, my App used SwiftData's MigraitonPlan, which caused it to crash when I opened it for the first time after updating in TestFlight or the store. After clicking it a second time, I could enter the App normally, and I could confirm that all the models were the latest versions.However, when I tested it in Xcode, everything was normal without any errors. Here is my MigrationPlan code: import Foundation import SwiftData enum MeMigrationPlan: SchemaMigrationPlan { static var schemas: [any VersionedSchema.Type] { [MeSchemaV1.self, MeSchemaV2.self, MeSchemaV3.self, MeSchemaV4.self] } static var stages: [MigrationStage] { [migrateV1toV2, migrateV2toV3, migrateV3toV4] } //migrateV1toV2, because the type of a data field in MeSchemaV1.TodayRingData.self was modified, the historical data was deleted during the migration, and the migration work was successfully completed. static let migrateV1toV2 = MigrationStage.custom( fromVersion: MeSchemaV1.self, toVersion: MeSchemaV2.self, willMigrate: { context in try context.delete(model: MeSchemaV1.TodayRingData.self) }, didMigrate: nil ) //migrateV2toV3, because a new Model was added, it would crash at startup when TF and the official version were updated, so I tried to delete the historical data during migration, but the problem still exists. static let migrateV2toV3 = MigrationStage.custom( fromVersion: MeSchemaV2.self, toVersion: MeSchemaV3.self, willMigrate: { context in try context.delete(model: MeSchemaV2.TodayRingData.self) try context.delete(model: MeSchemaV2.HealthDataStatistics.self) try context.delete(model: MeSchemaV2.SportsDataStatistics.self) try context.delete(model: MeSchemaV2.UserSettingTypeFor.self) try context.delete(model: MeSchemaV2.TodayRingData.self) try context.delete(model: MeSchemaV2.TodayHealthData.self) try context.delete(model: MeSchemaV2.SleepDataSource.self) try context.delete(model: MeSchemaV2.WorkoutTargetData.self) try context.delete(model: MeSchemaV2.WorkoutStatisticsForTarget.self) try context.delete(model: MeSchemaV2.HealthDataList.self) }, didMigrate: nil ) //migrateV3toV4, adds some fields in MeSchemaV3.WorkoutList.self, and adds several new Models. When TF and the official version are updated, it will crash at startup. Continue to try to delete historical data during migration, but the problem still exists. static let migrateV3toV4 = MigrationStage.custom( fromVersion: MeSchemaV3.self, toVersion: MeSchemaV4.self, willMigrate: { context in do { try context.delete(model: MeSchemaV3.WorkoutList.self) try context.delete(model: MeSchemaV3.HealthDataStatistics.self) try context.delete(model: MeSchemaV3.SportsDataStatistics.self) try context.delete(model: MeSchemaV3.UserSettingTypeFor.self) try context.delete(model: MeSchemaV3.TodayRingData.self) try context.delete(model: MeSchemaV3.TodayHealthData.self) try context.delete(model: MeSchemaV3.SleepDataSource.self) try context.delete(model: MeSchemaV3.WorkoutTargetData.self) try context.delete(model: MeSchemaV3.WorkoutStatisticsForTarget.self) try context.delete(model: MeSchemaV3.HealthDataList.self) try context.delete(model: MeSchemaV3.SleepStagesData.self) try context.save() } catch { print("Migration from V3 to V4 failed with error: \(error)") throw error } }, didMigrate: nil ) }
12
0
138
1d
SwiftData crash: PersistentModel.keyPathToString(keypath:)
I'm distributing an iOS (17.4+) and visionOS (1.2+) app via TestFlight that's using SwiftData. The most common crash by far is from SwiftData when deleting models from a context using a predicate (first snippet below), but so far I've been unable to reproduce it myself locally (second snippet below). I'm using SwiftData outside of SwiftUI views, via my own wrapper, and converting between my app models and SwiftData models. Does anyone have any ideas how I could potentially narrow this issue down (or reproduce), or know of any similar issues? Thanks! — Seb do { try context.transaction { context in let predicate = #Predicate<PersistedFeed> { $0.id == id } do { try context.delete(model: PersistedFeed.self, where: predicate) } catch { // .. Omitted for brevity } } } catch { // .. Omitted for brevity } Crash: Thread 0 Crashed: 0 libswiftCore.dylib 0x000000018dd558c0 _assertionFailure(_:_:file:line:flags:) + 264 (AssertCommon.swift:144) 1 SwiftData 0x000000022f7f323c static PersistentModel.keyPathToString(keypath:) + 1496 (DataUtilities.swift:0) 2 SwiftData 0x000000022f83312c PredicateExpressions.KeyPath.convert(state:) + 492 (FetchDescriptor.swift:394) 3 SwiftData 0x000000022f834a24 protocol witness for ConvertibleExpression.convert(state:) in conformance PredicateExpressions.KeyPath<A, B> + 16 (<compiler-generated>:0) 4 SwiftData 0x000000022f830a70 PredicateExpression.convertToExpressionOrPredicate(state:) + 724 (FetchDescriptor.swift:203) 5 SwiftData 0x000000022f831874 PredicateExpression.convertToExpression(state:) + 36 (FetchDescriptor.swift:217) 6 SwiftData 0x000000022f83b6c8 PredicateExpressions.Equal.convert(state:) + 328 7 SwiftData 0x000000022f8360ec protocol witness for ConvertibleExpression.convert(state:) in conformance PredicateExpressions.Equal<A, B> + 64 (<compiler-generated>:0) 8 SwiftData 0x000000022f830a70 PredicateExpression.convertToExpressionOrPredicate(state:) + 724 (FetchDescriptor.swift:203) 9 SwiftData 0x000000022f82fd60 PredicateExpression.convertToPredicate(state:) + 28 (FetchDescriptor.swift:224) 10 SwiftData 0x000000022f82edb4 nsPredicate<A>(for:) + 956 (FetchDescriptor.swift:88) 11 SwiftData 0x000000022f807c2c ModelContext.delete<A>(model:where:includeSubclasses:) + 596 (ModelContext.swift:1846) 12 SwiftData 0x000000022f81994c dispatch thunk of ModelContext.delete<A>(model:where:includeSubclasses:) + 56
0
0
82
5d
Is SwiftData's #Unique currently broken or am I missing something?
Hi, I am inserting two models where the "unique" attribute is the same. I was under the impression, that this should result in an upsert and not two inserts of the model, but that is not the case. See the test coding below for what I am doing (it is self contained, so if you want to try it out, just copy it into a test target). The last #expect statement fails because of the two inserts. Not sure if this is a bug (Xcode 16 beta 2 on Sonoma running an iOS 18 simulator) or if I am missing something here... // MARK: - UniqueItem - @Model final class UniqueItem { #Unique<UniqueItem>([\.no]) var timestamp = Date() var title: String var changed = false var no: Int init(title: String, no: Int) { self.title = title self.no = no } } // MARK: - InsertTests - @Suite("Insert Tests", .serialized) struct InsertTests { var sharedModelContainer: ModelContainer = { let schema = Schema([ UniqueItem.self, ]) let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false) do { return try ModelContainer(for: schema, configurations: [modelConfiguration]) } catch { fatalError("Could not create ModelContainer: \(error)") } }() @Test("Test unique.") @MainActor func upsertAndModify() async throws { let ctx = sharedModelContainer.mainContext try ctx.delete(model: UniqueItem.self) let item = UniqueItem(title: "Item \(1)", no: 0) ctx.insert(item) let allFD = FetchDescriptor<UniqueItem>() let count = try ctx.fetchCount(allFD) #expect(count == 1) let updatedItem = UniqueItem(title: "Item \(1)", no: 0) updatedItem.changed = true ctx.insert(updatedItem) // we should still have only 1 item because of the unique constraint let allCount = try ctx.fetchCount(allFD) #expect(allCount == 1) } }
0
1
93
5d
SwfitData Crashes after MigrationPlan Completed
There are multiple versions of VersionedSchema in my App. I used MigrationPlan to migrate data. It works well in Xcode, but in TestFlight and App Store, it always crashes when opening the App for the first time. MeMigrationPlan Code: import Foundation import SwiftData enum MeMigrationPlan: SchemaMigrationPlan { static var schemas: [any VersionedSchema.Type] { [MeSchemaV1.self, MeSchemaV2.self, MeSchemaV3.self, MeSchemaV4.self] } static var stages: [MigrationStage] { [migrateV1toV2, migrateV2toV3, migrateV3toV4] } //migrateV1toV2, because the type of a data field in MeSchemaV1.TodayRingData.self is modified, the historical data is deleted during migration, and the migration work is successfully completed. static let migrateV1toV2 = MigrationStage.custom( fromVersion: MeSchemaV1.self, toVersion: MeSchemaV2.self, willMigrate: { context in try context.delete(model: MeSchemaV1.TodayRingData.self) }, didMigrate: nil ) //migrateV2toV3, because a new Model was added, it would crash when starting up when TF and the official version were updated, so I tried to delete the historical data during migration, but the problem still exists. static let migrateV2toV3 = MigrationStage.custom( fromVersion: MeSchemaV2.self, toVersion: MeSchemaV3.self, willMigrate: { context in try context.delete(model: MeSchemaV2.TodayRingData.self) try context.delete(model: MeSchemaV2.HealthDataStatistics.self) try context.delete(model: MeSchemaV2.SportsDataStatistics.self) try context.delete(model: MeSchemaV2.UserSettingTypeFor.self) try context.delete(model: MeSchemaV2.TodayRingData.self) try context.delete(model: MeSchemaV2.TodayHealthData.self) try context.delete(model: MeSchemaV2.SleepDataSource.self) try context.delete(model: MeSchemaV2.WorkoutTargetData.self) try context.delete(model: MeSchemaV2.WorkoutStatisticsForTarget.self) try context.delete(model: MeSchemaV2.HealthDataList.self) }, didMigrate: nil ) //migrateV3toV4, adds some fields in MeSchemaV3.WorkoutList.self, and adds several new Models. When TF and the official version are updated, it will crash at startup. Continue to try to delete historical data during migration, but the problem still exists. static let migrateV3toV4 = MigrationStage.custom( fromVersion: MeSchemaV3.self, toVersion: MeSchemaV4.self, willMigrate: { context in do { try context.delete(model: MeSchemaV3.WorkoutList.self) try context.delete(model: MeSchemaV3.HealthDataStatistics.self) try context.delete(model: MeSchemaV3.SportsDataStatistics.self) try context.delete(model: MeSchemaV3.UserSettingTypeFor.self) try context.delete(model: MeSchemaV3.TodayRingData.self) try context.delete(model: MeSchemaV3.TodayHealthData.self) try context.delete(model: MeSchemaV3.SleepDataSource.self) try context.delete(model: MeSchemaV3.WorkoutTargetData.self) try context.delete(model: MeSchemaV3.WorkoutStatisticsForTarget.self) try context.delete(model: MeSchemaV3.HealthDataList.self) try context.delete(model: MeSchemaV3.SleepStagesData.self) try context.save() } catch { print("Migration from V3 to V4 failed with error: \(error)") throw error } }, didMigrate: nil ) }
1
0
59
5d
SwiftData via CloudKit Only Syncing Upon Relaunch
Hello I'm a new developer and am learning the ropes. I have an app that I'm testing and seem to have run into a bug. The data is syncing from one device to another, however it takes closing the app on the Mac or force closing the app on iOS/iPadOS to get the app to reflect the new data. Is there specific code I code share to help solve this issue or any suggestions that someone may have? Thank you ahead of time for your assistance. import SwiftData @main struct ApplicantProcessorApp: App { var sharedModelContainer: ModelContainer = { let schema = Schema([ Applicant.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() } .modelContainer(sharedModelContainer) } } struct ContentView: View { var body: some View { FilteredApplicantListView() } } #Preview { ContentView() .modelContainer(SampleData.shared.modelContainer) } struct FilteredApplicantListView: View { @State private var searchText = "" var body: some View { NavigationSplitView { ApplicantListView(applicantFilter: searchText) .searchable(text: $searchText, prompt: "Enter Name, Email, or Phone Number") .autocorrectionDisabled(true) } detail: { } } } import SwiftData struct ApplicantListView: View { @Environment(\.modelContext) private var modelContext @Query private var applicants: [Applicant] @State private var newApplicant: Applicant? init(applicantFilter: String = "") { // Filters } var body: some View { Group { if !applicants.isEmpty { List { ForEach(applicants) { applicant in NavigationLink { ApplicantView(applicant: applicant) } label: { HStack { VStack { HStack { Text(applicant.name) Spacer() } HStack { Text(applicant.phoneNumber) .font(.caption) Spacer() } HStack { Text(applicant.email) .font(.caption) Spacer() } HStack { Text("Expires: \(formattedDate(applicant.expirationDate))") .font(.caption) Spacer() } } if applicant.applicationStatus == ApplicationStatus.approved { Image(systemName: "checkmark.circle") .foregroundStyle(.green) .font(.title) } else if applicant.applicationStatus == ApplicationStatus.declined { Image(systemName: "xmark.circle") .foregroundStyle(.red) .font(.title) } else if applicant.applicationStatus == ApplicationStatus.inProgress { Image(systemName: "hourglass.circle") .foregroundStyle(.yellow) .font(.title) } else if applicant.applicationStatus == ApplicationStatus.waitingForApplicant { Image(systemName: "person.circle") .foregroundStyle(.yellow) .font(.title) } else { Image(systemName: "yieldsign") .foregroundStyle(.yellow) .font(.title) } } } } .onDelete(perform: deleteItems) } } else { ContentUnavailableView { Label("No Applicants", systemImage: "pencil.fill") } } } .navigationTitle("Applicants") .toolbar { ToolbarItem(placement: .navigationBarTrailing) { EditButton() } ToolbarItem { Button(action: addApplicant) { Label("Add Item", systemImage: "plus") } } } .sheet(item: $newApplicant) { applicant in NavigationStack { ApplicantView(applicant: applicant, isNew: true) } } } private func addApplicant() { withAnimation { let newItem = Applicant() modelContext.insert(newItem) newApplicant = newItem } } private func deleteItems(offsets: IndexSet) { withAnimation { for index in offsets { modelContext.delete(applicants[index]) } } } func formattedDate(_ date: Date) -> String { let dateFormatter = DateFormatter() dateFormatter.dateStyle = .short dateFormatter.timeStyle = .none return dateFormatter.string(from: date) } } import SwiftData @Model final class Applicant { var name = "" var email = "" var phoneNumber = "" var applicationDate = Date.now var expirationDate: Date { return Calendar.current.date(byAdding: .day, value: 90, to: applicationDate)! }
1
0
85
5d
SwiftData fatal error "Never access a full future backing data"
My app started crashing a ton with Xcode 16 beta 1 / iOS 18 because of "Thread 1: Fatal error: Never access a full future backing data". I was hoping this would be resolved with beta 2, but unfortunately this is not the case. I'm having a tough time reproducing this bug in a small sample project – I'd appreciate any hints as to what might be causing this. Full error: Thread 1: Fatal error: Never access a full future backing data - PersistentIdentifier(id: SwiftData.PersistentIdentifier.ID(url: x-coredata://10A5A93C-DC7F-40F3-92DB-F4125E1C7A73/MyType/p2), implementation: SwiftData.PersistentIdentifierImplementation) with Optional(3BF44A2D-256B-4C40-AF40-9B7518FD9FE6)
4
2
164
1d
How to embed SwiftData model container in a custom file package document type
Hi all, I have done a lot of research on this but am not able to come up with a workable solution. Background: I am trying to make an universal app on macOS/iOS that organizes media (image/video/pdf); think of its functionality like Apple's Photos app. So for my app document type, I would have my custom file package and within the package folder, there would be a SwiftData model container file and folders to hold user media. Approaches taken: DocumentGroup with SwiftData model then write directly into the file package In my App scene, I create document by having DocumentGroup(editing: .customDocument, migrationPlan: CustomMigrationPlan.self). This will create a document with a model container with my SwiftData model. And when I need to add media files into the document, I get the URL of the document, then use FileManager to write the file into the desired folder in the document. The result is that the media file is saved in the file package but then the SwiftData container is corrupted (all model data is reset to empty.) I am now trying to: 2. DocumentGroup with custom file package then try to embed SwiftData container In my current approach, I would create a document by having DocumentGroup(newDocument: CustomFileDocument()). I have custom FileDocument and FileWrapper. But the problem is I don't know how to embed a SwiftData container into my FileDocument. Is it possible to create a SwiftData model container when my FilerWrapper initialize? I can't figure out how to do this. Can anyone please advice on how I should accomplish this? Or if maybe I am looking at this problem wrongly? Do I need to use AppKit/UIKit with Core Data because it's currently not possible with SwiftUI/SwiftData? Thank you so much for reading and any input is greatly appreciated.
0
0
97
1w
iPadOS 18 Beta and SwiftData issues
I had a series of @Model classes with some mandatory attributes and some optional. Pre-move to 18, everything was working fine. After the migration, it reports that every single non-Optional attribute is nil upon trying to save. The error is CoreData related but not sure if its in the Core layer or Swift layer. Sample error (with app data removed) is : SwiftData.DefaultStore save failed with error: Error Domain=NSCocoaErrorDomain Code=1560 "Multiple validation errors occurred." Error Domain=NSCocoaErrorDomain Code=1570 \"%{PROPERTY}@ is a required value.\" UserInfo={NSValidationErrorObject=<NSManagedObject: 0x30388b2a0> NSLocalizedDescription=%{PROPERTY}@ is a required value., NSValidationErrorKey=systemName, NSValidationErrorValue=null}" I have modified the code to provide default values for all constructors in an attempt to see a difference, but get the same errors
0
1
147
1w
SwiftData adding INTs from records of the same date
Hi All, Looking for some help. I have an app that uses Charts and SwiftData. I have created @Query that filters the records and charts displays Ints in a line graph by the date. Easy. Most dates have two or more records. What I need to do is add all the ints from the same day and use that result in the chart. Any help you can send my way? Thanks so much. Blessings, --Mark
0
0
105
1w
SwiftData Update Item View from Background Thread
I have a background thread that is updating a swift data model Item using a ModelActor. The background thread runs processing an Item and updates the Item's status field. I notice that if I have a view like struct ItemListView: View { @Query private var items: [Items] var body: some View { VStack { ForEach(items) { item in ItemDetailView(item) } } } } struct ItemDetailView: View { var item: Item var body: some View { // expected: item.status automatically updates when the background thread updates the `Item`'s `status`. Text(item.status) // actual: This text never changes } } Then background updates to the Item's status in SwiftData does not reflect in the ItemDetailView. However, if I inline ItemDetailView in ItemListView like this: struct ItemListView: View { @Query private var items: [Items] var body: some View { VStack { ForEach(items) { item in // Put the contents of ItemDetailView directly in ItemListView Text(item.status) // result: item.status correctly updates when the background thread updates the item. } } } } Then the item's status text updates in the UI as expected. I suspect ItemDetailView does not properly update the UI because it just takes an Item as an input. ItemDetailView would need additional understanding of SwiftData, such as a ModelContext. Is there a way I can use ItemDetailView to show the Item's status and have the UI show the status as updated in the background thread? In case details about my background thread helps solve the problem, my thread is invoked from another view's controller like @Observable class ItemCreateController { func queueProcessingTask() { Task { let itemActor = ItemActor(modelContainer: modelContainer) await itemActor.setItem(item) await itemActor.process() } } } @ModelActor actor ItemActor { var item: Item? func setItem(_ item: Item) { self.item = modelContext.model(for: item.id) as? Item } func process() async { // task that runs processing on the Item and updates the Item's status as it goes. }
2
1
184
6d
SwiftData FatalError Unknown Relationship Key
Some of our users on iOS 17.5+ started to encounter crash due to: SwiftData/BackingData.swift:669: Fatal error: Unknown Relationship Key - subscription) We have tried using SwiftData on the MainActor only but an issues still effects some of our users. Our models look like these: @Model public final class ProfileModel { public static let fetchDescriptor = FetchDescriptor<ProfileModel>.self public enum Gender: Codable { case female case male case other } public enum Units: Codable { case imperial case metric } public enum Eating: Codable { case empath case enthusiast case explorer case guardian case harmonizer case pacifier case regulator case stoic case iosDefault } public enum RegistrationSource: Codable { case iOS case web } public enum NHE: Codable { case combined case emotional case mindless } public enum Goal: Codable { case beHealthier case energyIncrease case healthyHabits case looseWeight case relationshipsWithFood } public enum WeightLossFocus: Codable { case activity case healthyHabits case nutrition case other } @Attribute(.unique) public let id: String public let isPaid: Bool public let eating: Eating public let registrationSource: RegistrationSource public let nhe: NHE? public let firstName: String? public let lastName: String? public let gender: Gender? public let height: String? public let age: Int? public let weight: String? public let targetWeight: String? public let bmi: String? public let goal: Goal? public let units: Units? public let weightLossFocus: WeightLossFocus? @Relationship(deleteRule: .cascade) public var subscription: ProfileSubscriptionModel? public init( id: String, isPaid: Bool, eating: Eating, registrationSource: RegistrationSource, nhe: NHE?, firstName: String?, lastName: String?, gender: Gender?, height: String?, age: Int?, weight: String?, targetWeight: String?, bmi: String?, goal: Goal?, units: Units?, weightLossFocus: WeightLossFocus?, subscription: ProfileSubscriptionModel? ) { self.id = id self.isPaid = isPaid self.eating = eating self.registrationSource = registrationSource self.nhe = nhe self.firstName = firstName self.lastName = lastName self.gender = gender self.height = height self.age = age self.weight = weight self.targetWeight = targetWeight self.bmi = bmi self.goal = goal self.units = units self.weightLossFocus = weightLossFocus self.subscription = subscription } } @Model public final class ProfileSubscriptionModel { public static let fetchDescriptor = FetchDescriptor<ProfileSubscriptionModel>.self public let price: Double public let currency: String public let period: Int public let status: String public let expirationDate: Date public let cancelledAt: Date? public init(price: Double, currency: String, period: Int, status: String, expirationDate: Date, cancelledAt: Date?) { self.price = price self.currency = currency self.period = period self.status = status self.expirationDate = expirationDate self.cancelledAt = cancelledAt } }
0
0
147
1w
SwiftData - Context missing for optional
I have encountered an issue that when using a ModelActor to sync data in the background, the app will crash if one of the operations is to remove a PersistentModel from the context. This is running on the latest beta of Xcode 16 with visionOS 1.2 as target and in Swift 6 language mode. The code is being executed in a ModelActor. The error is first thrown by: #5 0x00000001c3223280 in PersistentModel.getValue<τ_0_0>(forKey:) () Thread 1: Fatal error: Context is missing for Optional(SwiftData.PersistentIdentifier(id: SwiftData.PersistentIdentifier.ID(url: x-coredata://97AA86BC-475D-4509-9004-D1182ABA1922/Reminder/p303), implementation: SwiftData.PersistentIdentifierImplementation)) func globalSync() async { await fetchAndSyncFolders() let result = await fetchReminders() switch result { case .success(let ekReminders): var localReminders = (try? await fetch(FetchDescriptor<Reminder>())) ?? [] // Handle local reminders with nil ekReminderID by creating new EKReminders for them for reminder in localReminders { if reminder.ekReminderID == nil { await self.createEkReminder(reminder: reminder) } } // Re-fetch local reminders to include newly created EKReminderIDs localReminders = (try? await fetch(FetchDescriptor<Reminder>())) ?? [] var localReminderDict = [String: Reminder]() for reminder in localReminders { if let ekReminderID = reminder.ekReminderID { if let existingReminder = localReminderDict[ekReminderID] { self.delete(model: existingReminder) } else { localReminderDict[ekReminderID] = reminder } } } let ekReminderDict = createReminderLookup(byID: ekReminders) await self.syncReminders(localReminders: Array(localReminderDict.values), localReminderDict: localReminderDict, ekReminderDict: ekReminderDict) // Merge duplicates await self.mergeDuplicates(localReminders: localReminders) save() case .failure(let error): print("Failed to fetch reminders: \(error.localizedDescription)") } }
0
5
169
1w
`Task` at `createSampleData` function in What's new in SwiftData session
I was looking to the example code that point from What's new in SwiftData session and noticed something that I cannot understand about Swift concurrency. from this snippet: static func createSampleData(into modelContext: ModelContext) { Task { @MainActor in let sampleDataTrips: [Trip] = Trip.previewTrips let sampleDataLA: [LivingAccommodation] = LivingAccommodation.preview let sampleDataBLT: [BucketListItem] = BucketListItem.previewBLTs let sampleData: [any PersistentModel] = sampleDataTrips + sampleDataLA + sampleDataBLT sampleData.forEach { modelContext.insert($0) } if let firstTrip = sampleDataTrips.first, let firstLivingAccommodation = sampleDataLA.first, let firstBucketListItem = sampleDataBLT.first { firstTrip.livingAccommodation = firstLivingAccommodation firstTrip.bucketList.append(firstBucketListItem) } if let lastTrip = sampleDataTrips.last, let lastBucketListItem = sampleDataBLT.last { lastTrip.bucketList.append(lastBucketListItem) } try? modelContext.save() } } From the code snippet, I cannot see any task that needs to be marked with await, and it is also marked as @MainActor. My question is: why do we need to put Task here? It seems like all the code will run on the main thread anyway. I am just afraid that I might be missing some concept of Swift concurrency or SwiftData here. Thank you
2
0
213
1w