I have an issue in my app, where the crashing frame is an assertionFailure in BackingData.set inside SwiftData framework. My own app doesn't appear until frame 14. I have no idea what causes this, or even how to create a reproducible project as this only happens on some devices.
The frame prior to the assertionFailure is this:
#1 (null) in BackingData.set(any:value:) ()
It seems like there is a backing data encoding happening in my Model class, and some value is causing it to fail. The model being accessed is through a relationship, and the frame in the app crashing is along the lines of
Text(parent.child.name)
Obviously, something is wrong in how I have made child, but the part that stand out to me is the assertionFailure in a release build
How did we do? We’d love to know your thoughts on this year’s conference. Take the survey here
SwiftData
RSS for tagSwiftData 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
I'm a first time developer for Swift, (getting on a bit!) but after programming in VB back in the late 90s I wanted to write an app for iPhone. I think I might have gone about it the wrong way, but I've got an app that works great on my iPhone or works great on my iPad. It saves the data persistently on device, but, no matter how much I try, what I read and even resorting to AI (ChatGPT & Gemini) I still can't get it to save the data on iCloud to synchronise between the two and work across the devices. I think it must be something pretty fundamental I'm doing (or more likely not doing) that is causing the issue.
I'm setting up my signing and capabilities as per the available instructions but I always get a fatal error. I think it might be something to do with making fields optional, but at this point I'm second guessing myself and feeling a complete failure. Any advice or pointers would be really gratefully appreciated. I like my app and would like eventually to get it on the App Store but at this point in time I feel it should be on the failed projects heap!
I've even tried a new Xcode project for iOS and asking it to use SwiftData and CloudKit - the default project should work - right? But it absolutely doesn't for me. Please send help!!
I am working with SwiftData and get the below error. I can't find any documentation on it to see what to fix. Any help would be appreciated.
Fatal error: This relationship already has a value but it's not the target:
I'm developing a medication scheduling app similar to Apple Health's Medications feature, and I'd like some input on my current approach to background tasks.
In my app, when a user creates a medication, I generate ScheduledDose objects (with corresponding local notifications) for the next 2 weeks and save them to SwiftData. To ensure this 2-week window stays current, I've implemented a BGAppRefreshTask that runs daily to generate new doses as needed.
My concern is whether BGAppRefreshTask is the appropriate mechanism for this purpose. Since I'm not making any network requests but rather generating and storing local data, I'm questioning if this is the right approach.
I'm also wondering how Apple Health's Medications feature handles this kind of scheduling. Their app seems to maintain future doses regardless of app usage patterns.
Has anyone implemented something similar or can suggest the best background execution API for this type of scenario?
Thanks for any guidance you can provide.
Topic:
App & System Services
SubTopic:
Processes & Concurrency
Tags:
HealthKit
SwiftUI
Background Tasks
SwiftData
I’m trying to build a CRUD app using SwiftData, @Query model and multidatepicker.
The data from a multidatepicker is stored or persists in SwiftData as Set = [].
My current dilemma is how to use SwiftData and @Query model Predicate to find all records on the current date.
I can’t find any SwiftData documentation or examples @Query using Set = [].
My CRUD app should retrieve all records for the current date. Unfortunately, I don’t know the correct @Query model syntax for Set = [].
Definitely one of the stranger quirks of SwiftData I've come across.
I have a ScriptView that shows Line entities related to a Production, and a TextEnterScriptView that’s presented in a sheet to input text.
I’m noticing that every time I type in the TextEditor within TextEnterScriptView, a new Line shows up in ScriptView — even though I haven’t explicitly inserted it into the modelContext.
I'm quite confused because even though I’m only assigning a new Line to a local @State array in TextEnterScriptView, every keystroke in the TextEditor causes a duplicate Line to appear in ScriptView.
In other words, Why is SwiftData creating new Line entities every time I type in the TextEditor, even though I’m only assigning to a local @State array and not explicitly inserting them into the modelContext?
Here is my minimal reproducible example:
import SwiftData
import SwiftUI
@main
struct testApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.modelContainer(for: Line.self, isAutosaveEnabled: false)
}
}
}
struct ContentView: View {
@Environment(\.modelContext) var modelContext
@Query(sort: \Production.title) var productions: [Production]
var body: some View {
NavigationStack {
List(productions) { production in
NavigationLink(value: production) {
Text(production.title)
}
}
.navigationDestination(for: Production.self) { production in
ScriptView(production: production)
}
.toolbar {
Button("Add", systemImage: "plus") {
let production = Production(title: "Test \(productions.count + 1)")
modelContext.insert(production)
do {
try modelContext.save()
} catch {
print(error)
}
}
}
.navigationTitle("Productions")
}
}
}
struct ScriptView: View {
@Query private var lines: [Line]
let production: Production
@State private var isShowingSheet: Bool = false
var body: some View {
List {
ForEach(lines) { line in
Text(line.content)
}
}
.toolbar {
Button("Show Sheet") {
isShowingSheet.toggle()
}
}
.sheet(isPresented: $isShowingSheet) {
TextEnterScriptView(production: production)
}
}
}
struct TextEnterScriptView: View {
@Environment(\.dismiss) var dismiss
@State private var text = ""
@State private var lines: [Line] = []
let production: Production
var body: some View {
NavigationStack {
TextEditor(text: $text)
.onChange(of: text, initial: false) {
lines = [Line(content: "test line", production: production)]
}
.toolbar {
Button("Done") {
dismiss()
}
}
}
}
}
@Model
class Production {
@Attribute(.unique) var title: String
@Relationship(deleteRule: .cascade, inverse: \Line.production)
var lines: [Line] = []
init(title: String) {
self.title = title
}
}
@Model
class Line {
var content: String
var production: Production?
init(content: String, production: Production?) {
self.content = content
self.production = production
}
}
Context:
The SwiftUI @Query macro has an internal modelContext.
The ModelActor also has a modelContext, from which the data should be read/written.
Issue:
When writing to @Model data fetched with @Query macro using a ModelActor, it will crash in the most not-obvious ways.
Also, fetching @Model with ModelActor will result in errors in Swift 6 since @Model aren't sendable.
Problem to Solve:
- How to write a good amount of data to SwiftData/CoreData without blocking the UI thread?
Would the recommendation from the Apple team be that a large amount of data should be read/written with ModelActor and a small amount should be done with the @Query's internal modelContext ?
The following complex migration consistently crashes the app with the following error:
SwiftData/PersistentModel.swift:726: Fatal error: What kind of backing data is this? SwiftData._KKMDBackingData<SwiftDataMigration.ItemSchemaV1.ItemList>
My app relies on a complex migration that involves these optional 1 to n relationships. Theoretically I could not assign the relationships in the willMigrate block but afterwards I am not able to tell which list and items belonged together.
Steps to reproduce:
Run project
Change typealias CurrentSchema to ItemSchemaV2 instead of ItemSchemaV1.
Run project again -> App crashes
My setup:
Xcode Version 16.2 (16C5032a)
MacOS Sequoia 15.4
iPhone 12 with 18.3.2 (22D82)
Am I doing something wrong or did I stumble upon a bug? I have a demo Xcode project ready but I could not upload it here so I put the code below.
Thanks for your help
typealias CurrentSchema = ItemSchemaV1
typealias ItemList = CurrentSchema.ItemList
typealias Item = CurrentSchema.Item
@main
struct SwiftDataMigrationApp: App {
var sharedModelContainer: ModelContainer = {
do {
return try ModelContainer(for: ItemList.self, migrationPlan: MigrationPlan.self)
} catch {
fatalError("Could not create ModelContainer: \(error)")
}
}()
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(sharedModelContainer)
}
}
This is the migration plan
enum MigrationPlan: SchemaMigrationPlan {
static var schemas: [any VersionedSchema.Type] {
[ItemSchemaV1.self, ItemSchemaV2.self]
}
static var stages: [MigrationStage] = [
MigrationStage.custom(fromVersion: ItemSchemaV1.self, toVersion: ItemSchemaV2.self, willMigrate: { context in
print("Started migration")
let oldlistItems = try context.fetch(FetchDescriptor<ItemSchemaV1.ItemList>())
for list in oldlistItems {
let items = list.items.map { ItemSchemaV2.Item(timestamp: $0.timestamp)}
let newList = ItemSchemaV2.ItemList(items: items, name: list.name, note: "This is a new property")
context.insert(newList)
context.delete(list)
}
try context.save() // Crash indicated here
print("Finished willMigrate")
}, didMigrate: { context in
print("Did migrate successfully")
})
]
}
The versioned schemas
enum ItemSchemaV1: VersionedSchema {
static var versionIdentifier = Schema.Version(1, 0, 0)
static var models: [any PersistentModel.Type] {
[Item.self]
}
@Model
final class Item {
var timestamp: Date
var list: ItemSchemaV1.ItemList?
init(timestamp: Date) {
self.timestamp = timestamp
}
}
@Model
final class ItemList {
@Relationship(deleteRule: .cascade, inverse: \ItemSchemaV1.Item.list)
var items: [Item]
var name: String
init(items: [Item], name: String) {
self.items = items
self.name = name
}
}
}
enum ItemSchemaV2: VersionedSchema {
static var versionIdentifier = Schema.Version(2, 0, 0)
static var models: [any PersistentModel.Type] {
[Item.self]
}
@Model
final class Item {
var timestamp: Date
var list: ItemSchemaV2.ItemList?
init(timestamp: Date) {
self.timestamp = timestamp
}
}
@Model
final class ItemList {
@Relationship(deleteRule: .cascade, inverse: \ItemSchemaV2.Item.list)
var items: [Item]
var name: String
var note: String
init(items: [Item], name: String, note: String = "") {
self.items = items
self.name = name
self.note = note
}
}
}
Last the ContentView:
struct ContentView: View {
@Query private var itemLists: [ItemList]
var body: some View {
NavigationSplitView {
List {
ForEach(itemLists) { list in
NavigationLink {
List(list.items) { item in
Text(item.timestamp.formatted(date: .abbreviated, time: .complete))
}
.navigationTitle(list.name)
} label: {
Text(list.name)
}
}
}
.navigationTitle("Crashing migration demo")
.onAppear {
if itemLists.isEmpty {
for index in 0..<10 {
let items = [Item(timestamp: Date.now)]
let listItem = ItemList(items: items, name: "List No. \(index)")
modelContext.insert(listItem)
}
try! modelContext.save()
}
}
} detail: {
Text("Select an item")
}
}
}
I've noticed that SwiftData's @Relationship seems to potentially cause application crashes.
The crash error is shown in the image.
Since this crash appears to be random and I cannot reproduce it under specific circumstances, I can only temporarily highlight that this issue seems to exist.
@Model final class TrainInfo {
@Relationship(deleteRule: .cascade, inverse: \StopStation.trainInfo)
var stations: [StopStation]?
}
@Model final class StopStation {
@Relationship
var trainInfo: TrainInfo?
}
/// some View
var origin: StopStationDisplayable? {
if let train = train as? TrainInfo {
return train.stations?.first(where: { $0.isOrigin }) ?? train.stations?.first(where: { $0.isStarting })
}
return nil
}
// Some other function or property
func someFunction() {
if let origin, let destination {
// Function implementation
}
}
If use a SortDescriptor for a model and sort by some attribute from a relationship, in DEBUG mode it all works fine and sorts. However, in release mode, it is an instant crash.
SortDescriptor(.name, order: .reverse) ---- works
SortDescriptor(.assignedUser?.name, order: .reverse) ---- works in debug but crash in release.
What is the issue here, is it that SwiftData just incompetent to do this?
Setup
I am running a versionedSchema for my SwiftData model and attempting a migration. The new version contains a new attribute, with a type of a new custom enum defined in the @Model class, a default value, and a private(set). Migration was completed with a migrationPlan with nil values for willMigrate and didMigrate.
Example - Previous Version
@Model
class MyNumber {
var num: Int
init() {
// Init Code
}
}
Example - Newest Version
@Model
class MyNumber {
var num: Int
private(set) var rounding: RoundAmount = MyNumber.RoundAmount.thirtyMinute
init() {
// Init Code
}
enum RoundAmount {
case fiveMinute, tenMinute, thirtyMinute
}
}
Issue
Running this code, I get a swiftData error for “SwiftData/ModelCoders.swift:1585: nil value passed for a non-optional keyPath, /MyNumber.rounding”
I assume this means a failure of the swiftData lightweight migration? I have reverted the version, removed private(set) and re-tried the migration with no success.
Using the versionedSchema with migrationPlans, are lightweight migrations possible? Could this be an issue with the use of a custom enum? Other changes in my actual project migrated successfully so I’m lost on why I’m having this issue.
Hi there, I got two models here:
Two Models, with Many-To-Many Relationship
@Model
final class PresetParams: Identifiable {
@Attribute(.unique) var id: UUID = UUID()
var positionX: Float = 0.0
var positionY: Float = 0.0
var positionZ: Float = 0.0
var volume: Float = 1.0
@Relationship(deleteRule: .nullify, inverse: \Preset.presetAudioParams)
var preset = [Preset]()
init(position: SIMD3<Float>, volume: Float) {
self.positionX = position.x
self.positionY = position.y
self.positionZ = position.z
self.volume = volume
self.preset = []
}
var position: SIMD3<Float> {
get {
return SIMD3<Float>(x: positionX, y: positionY, z: positionZ)
}
set {
positionX = newValue.x
positionY = newValue.y
positionZ = newValue.z
}
}
}
@Model
final class Preset: Identifiable {
@Attribute(.unique) var id: UUID = UUID()
var presetName: String
var presetDesc: String?
var presetAudioParams = [PresetParams]() // Many-To-Many Relationship.
init(presetName: String, presetDesc: String? = nil) {
self.presetName = presetName
self.presetDesc = presetDesc
self.presetAudioParams = []
}
}
To be honest, I don't fully understand how the @Relationship thing works properly in a Many-To-Many relationship situation. Some tutorials suggest that it's required on the "One" side of an One-To-Many Relationship, while the "Many" side doesn't need it.
And then there is an ObservableObject called "ModelActors" to manage all ModelActors, ModelContainer, etc.
ModelActors, ModelContainer...
class ModelActors: ObservableObject {
static let shared: ModelActors = ModelActors()
let sharedModelContainer: ModelContainer
private init() {
var schema = Schema([
// ...
Preset.self,
PresetParams.self,
// ...
])
do {
sharedModelContainer = try ModelContainer(for: schema, migrationPlan: MigrationPlan.self)
} catch {
fatalError("Could not create ModelContainer: \(error.localizedDescription)")
}
}
}
And there is a migrationPlan:
MigrationPlan
// MARK: V102
// typealias ...
// MARK: V101
typealias Preset = AppSchemaV101.Preset
typealias PresetParams = AppSchemaV101.PresetParams
// MARK: V100
// typealias ...
enum MigrationPlan: SchemaMigrationPlan {
static var schemas: [VersionedSchema.Type] {
[
AppSchemaV100.self,
AppSchemaV101.self,
AppSchemaV102.self,
]
}
static var stages: [MigrationStage] {
[AppMigrateV100toV101, AppMigrateV101toV102]
}
static let AppMigrateV100toV101 = MigrationStage.lightweight(fromVersion: AppSchemaV100.self, toVersion: AppSchemaV101.self)
static let AppMigrateV101toV102 = MigrationStage.lightweight(fromVersion: AppSchemaV101.self, toVersion: AppSchemaV102.self)
}
// MARK: Here is the AppSchemaV101
enum AppSchemaV101: VersionedSchema {
static var versionIdentifier: Schema.Version = Schema.Version(1, 0, 1)
static var models: [any PersistentModel.Type] {
return [ // ...
Preset.self,
PresetParams.self
]
}
}
Fails on iOS 18.3.x: "Failed to fulfill link PendingRelationshipLink"
So I expected the SwiftData subsystem to work correctly with version control. A good news is that on iOS 18.1 it does work. But it fails on iOS 18.3.x with a fatal Error:
"SwiftData/SchemaCoreData.swift:581: Fatal error: Failed to fulfill link PendingRelationshipLink(relationshipDescription: (<NSRelationshipDescription: 0x30377fe80>), name preset, isOptional 0, isTransient 0, entity PresetParams, renamingIdentifier preset, validation predicates (), warnings (), versionHashModifier (null)userInfo {}, destination entity Preset, inverseRelationship (null), minCount 0, maxCount 0, isOrdered 0, deleteRule 1, destinationEntityName: "Preset", inverseRelationshipName: Optional("presetAudioParams")), couldn't find inverse relationship 'Preset.presetAudioParams' in model"
Fails on iOS 17.5: Another Error
I tested it on iOS 17.5 and found another issue: Accessing or mutating the "PresetAudioParams" property causes the SwiftData Macro Codes to crash, affecting both Getter and Setter. It fails with an error:
"EXC_BREAKPOINT (code=1, subcode=0x1cc1698ec)"
Tweaking the @Relationship marker and ModelContainer settings didn't fix the problem.
Hi,
I am creating (or trying to) my first app using SwiftData - and I have questions :-)
The main question I can't get my head wrapped around is the following:
Let's say I have the sample below...
@Model
class Person {
@Relationship(inverse:\Hat.owner) var hat:Hat
}
@Model
class Hat {
var owner:Person?
}
It looks like I am creating a strong reference cycle between the person and the hat objects? And in fact I am seeing these kinds of reference cycles when I look at the memory debugger.
Many code samples I have seen so far use this type of relationship declaration...
And I am wondering: Am I missing something?
Admittedly I don't find many discussions about memory leaks caused by SwiftData despite the syntax being used in many examples?
So what is the situation? Did Apple just miss to explain that the inverse: declaration causes memory leaks or is there some kind of magic that I should understand?
I attempted to create a SortDescriptor using a method in enum to sort various different models in SwiftUI lists.
But it causes crashes in Xcodes previews but not in the simulator, and I don't know why.
Maybe someone could suggest changes.
extension Item:ListSorting {} //List sorting is a protocol given to various Models
enum ListSortingStyle<T>:String,CaseIterable where T:ListSorting {
case alphabetical = "A…Z"
case alphabeticalReverse = "Z…A"
case createDate = "Newest"
case createDateReverse = "Oldest"
case editDate = "Latest Edit"
case editDateReverse = "Oldest Edit"
/// Returns a SortDescriptor matching the enumeration
func sortDescriptor() -> SortDescriptor<T> {
switch self {
case .alphabetical:
SortDescriptor<T>(\.name, comparator: .localized, order: .forward)
case .alphabeticalReverse:
SortDescriptor<T>(\.name, comparator: .localized, order: .reverse)
case .createDate:
SortDescriptor<T>(\.creationDate, order: .forward)
case .createDateReverse:
SortDescriptor<T>(\.creationDate, order: .reverse)
case .editDate:
SortDescriptor<T>(\.editDate, order: .forward)
case .editDateReverse:
SortDescriptor<T>(\.editDate, order: .reverse)
}
}
}
Which is used in
struct ItemsList: View {
@Environment(\.modelContext) private var modelContext
@Query private var items:[Item] = []
init(sortStyle:ListSortingStyle<Item> = .alphabetical) {
let sortDescriptor = SortDescriptor<Item>(\.name, comparator: .localized, order: .forward) //(1) This works in preview & simulator
//OR
let sortDescriptor2 = sortStyle.sortDescriptor() //(2) This crashes in a preview when used in a fetch not in the iOS simulator
print(sortDescriptor,sortDescriptor2)
let descriptor = FetchDescriptor<Item>(sortBy:[sortDescriptor2])
self._items = Query(descriptor)
}
var body: some View {
...
}
}
As far as I can see both methods create a SortDiscriptor. If I print the sortDescriptor variable in they look almost identical:
//1
SortDescriptor<Item>(
order: Foundation.SortOrder.forward,
keyString: nil,
comparison: Foundation.SortDescriptor<MyApp.Item>.AllowedComparison.comparableString(
(extension in Foundation):Swift.String.StandardComparator(options: __C.NSStringCompareOptions(rawValue: 0),
isLocalized: true,
order: Foundation.SortOrder.forward),
\Item. <computed 0x0000000340213b18 (String)>)
)
//2
SortDescriptor<Item>(
order: Foundation.SortOrder.forward,
keyString: nil,
comparison: Foundation.SortDescriptor<MyApp.Item>.AllowedComparison.comparableString(
(extension in Foundation):Swift.String.StandardComparator(options: __C.NSStringCompareOptions(rawValue: 0),
isLocalized: true,
order: Foundation.SortOrder.forward),
\Item.<computed 0x0000000340022174 (String)>)
)
But the one created with the generic method on the enum crashes with the error message:
CrashReportError: Fatal Error in DataUtilities.swift
MyApp crashed due to fatalError in DataUtilities.swift at line 64.
Couldn't find \Item.<computed 0x0000000340022174 (String)> on Item with fields [SwiftData.Schema.PropertyMetadata ...
How do I filter data using @Query with a Set of DateComponents? I successfully saved multiple dates using a MultiDatePicker in AddView.swift. In ListView.swift, I want to retrieve all records for the current or today’s date.
There are hundreds of examples using @Query with strings and dates, but I haven’t found an example of @Query using a Set of DateComponents
Nothing will compile and after hundreds and hundreds of attempts, my hair is turning gray.
Please, please, please help me.
For example, if the current date is Tuesday, March 4 205, then I want to retrieve both records. Since both records contain Tuesday, March 4, then retrieve both records. Sorting works fine because the order by clause uses period which is a Double.
Unfortunately, my syntax is incorrect and I don’t know the correct predicate syntax for @Query and a Set of DateComponents.
Class Planner.swift file
import SwiftUI
import SwiftData
@Model
class Planner {
//var id: UUID = UUID()
var grade: Double = 4.0
var kumi: Double = 4.0
var period: Double = 1.0
var dates: Set<DateComponents> = []
init(
grade: Double = 4.0, kumi: Double = 4.0, period: Double = 1.0, dates: Set<DateComponents> = []
)
{
self.grade = grade
self.kumi = kumi
self.period = period
self.dates = dates
}
}
@Query Model snippet of code does not work
The compile error is to use a Set of DateComponents, not just DateComponents.
@Query(filter: #Predicate<Planner> { $0.dates = DateComponents(calendar: Calendar.current, year: 2025, month: 3, day: 4)},
sort: [SortDescriptor(\Planner.period)])
var planner: [Planner]
ListView.swift image
EditView.swift for record #1
DB Browser for SQLlite: record #1 (March 6, 2025 and March 4, 2025)
[{"isLeapMonth":false,"year":2025,"day":6,"month":3,"calendar":{"identifier":"gregorian","minimumDaysInFirstWeek":1,"current":1,"locale":{"identifier":"en_JP","current":1},"firstWeekday":1,"timeZone":{"identifier":"Asia\/Tokyo"}},"era":1},{"month":3,"year":2025,"day":4,"isLeapMonth":false,"era":1,"calendar":{"locale":{"identifier":"en_JP","current":1},"timeZone":{"identifier":"Asia\/Tokyo"},"current":1,"identifier":"gregorian","firstWeekday":1,"minimumDaysInFirstWeek":1}}]
EditView.swift for record #2
DB Browser for SQLlite: record #2 (March 3, 2025 and March 4, 2025)
[{"calendar":{"minimumDaysInFirstWeek":1,"locale":{"current":1,"identifier":"en_JP"},"timeZone":{"identifier":"Asia\/Tokyo"},"firstWeekday":1,"current":1,"identifier":"gregorian"},"month":3,"day":3,"isLeapMonth":false,"year":2025,"era":1},{"year":2025,"month":3,"era":1,"day":4,"isLeapMonth":false,"calendar":{"identifier":"gregorian","current":1,"firstWeekday":1,"minimumDaysInFirstWeek":1,"timeZone":{"identifier":"Asia\/Tokyo"},"locale":{"current":1,"identifier":"en_JP"}}}]
Any help is greatly appreciated.
I'm trying to find a way to create and use a test cloudkit container in my swiftdata-backed app.
I want to test pre-filling the model container with localized content at first run.
To do this I created a test cloudkit container, and assigned it to my debug build profile in settings and capabilities.
I then conditionally reference the test container in my apps cloudkit manager, i.e.:
private let db: CKDatabase
init() {
#if DEBUG
let container = CKContainer(identifier: "iCloud.com.team-name.myappname.testing-de") // Test CloudKit container
#else
let container = CKContainer(identifier: "iCloud.com.team-name.myappname") // Production CloudKit container
#endif
self.db = container.privateCloudDatabase
}
But when I run my app in debug, content is still created in the primary/production container.
Am I missing something? Or is there a better, or documented, way to test cloudkit more robustly?
For a CRM application, I want users to be able to switch between accounts and have their saved contacts stored locally. Whenever a user logs in, the app should fetch data from their specific database location.
What’s the best practice to achieve this?
Should I create a separate database for each user?
Should I store all the data in one database and filter it by user?
Or is there a better approach I should consider?
Is there a way to move user data from UserDefaults to SwiftData when the app is in production so that people don’t lose their data. Currently my audio journals in my journal app has everything in the UserDefaults. Now this is bad for obvious reasons but I was thinking if there was a way. It’s only been 1 week since published and I have already had17 people download it.
I want to get to a point where I can use a small view with a query for my SwiftData model like this:
@Query
private var currentTrainingCycle: [TrainingCycle]
init(/*currentDate: Date*/) {
_currentTrainingCycle = Query(filter: #Predicate<TrainingCycle> {
$0.numberOfDays > 0
// $0.startDate < currentDate && currentDate < $0.endDate
}, sort: \.startDate)
}
The commented code is where I want to go. In this instance, it'd be created as a lazy var in a viewModel to have it stable (and not constantly re-creating the view). Since it was not working, I thought I could check the same view with a query that does not require any dynamic input. In this case, the numberOfDays never changes after instantiation.
But still, each time the app tries to create this view, the app becomes unresponsive, the CPU usage goes at 196%, memory goes way high and the device heats up quickly.
Am I holding it wrong? How can I have a dynamic predicate on a View in SwiftUI with SwiftData?
Using SwiftData and this is the simplest example I could boil down:
@Model
final class Item {
var timestamp: Date
var tag: Tag?
init(timestamp: Date) {
self.timestamp = timestamp
}
}
@Model
final class Tag {
var timestamp: Date
init(timestamp: Date) {
self.timestamp = timestamp
}
}
Notice Tag has no reference to Item.
So if I create a bunch of items and set their Tag. Later on I add the ability to delete a Tag. Since I haven't added inverse relationship Item now references a tag that no longer exists so so I get these types of errors:
SwiftData/BackingData.swift:875: Fatal error: This model instance was invalidated because its backing data could no longer be found the store. PersistentIdentifier(id: SwiftData.PersistentIdentifier.ID(url: x-coredata://EEC1D410-F87E-4F1F-B82D-8F2153A0B23C/Tag/p1), implementation: SwiftData.PersistentIdentifierImplementation)
I think I understand now that I just need to add the item reference to Tag and SwiftData will nullify all Item references to that tag when a Tag is deleted.
But, the damage is already done. How can I iterate through all Items that referenced a deleted tag and set them to nil or to a placeholder Tag? Or how can I catch that error and fix it when it comes up?
The crash doesn't occur when loading an Item, only when accessing item.tag?.timestamp, in fact, item.tag?.id is still ok and doesn't crash since it doesn't have to load the backing data.
I've tried things like just looping through all items and setting tag to nil, but saving the model context fails because somewhere in there it still tries to validate the old value.
Thanks!