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
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
When user triggers a sheet of a view, it's quite easy to deal with its confirmation action. However, how can I deal with the cancellation action, which means when user taps the cancel button, what they edits can re-become its original version ( I am using SwiftData)?
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
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.
}
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
}
}
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)")
}
}
Sorry this post is duplicate
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
I want to display my own image in an inline widget. Using the SwiftUI Image syntax doesn't show the image, so following advice from online forums, I used the syntaxImage(uiImage: UIImage(named: String))This
successfully displays the image, but if I change the image file name in the app, the image doesn't update properly.
I tested displaying the image file name using Text in the inline widget, and it correctly shows the updated file name from my app. So, my AppStorage and AppGroups seem to be working correctly.
I'd like to ask if there's a way to update my images properly and if there's an alternative method to display images without converting them to UIImage. Thanks.
I'm creating an application with swiftui which gets images and videos from the Photos picker then store them with swiftData for later use.
I save both images and videos as data with @Attribute(.externalStorage).
But it just seems wrong to me to store the videos that way, they can be several gigabytes in size . What is the correct way to handle something like this ? Is it to store the url and then each time the user wants to see a video save a temporary video ?. If that's the case can anyone show me how this should be done?
Any comments appreciated
Guillermo
I have a model that has a unique property, e.g.:
@Model
final class UserWord
@Attribute(.unique)
let word: String
let partOfSpeech: PartOfSpeech
let metaData: ...
At the end of the init I have this:
init(...) {
if partOfSpeech == .verb {
metaData = fetchMeta()
}
}
This works fine when a word is newly created and saved. But let's say there's a unique conflict and a user tries to save a new entry with the same word. Apparently this init still fires and fetchMeta edits the existing entry which gives me the error:
CoreData: error: Mutating a managed object 0xb890d8167c911ade <x-coredata://4C75194F-D923-477F-BB22-ACBDECCD7530/UserWord/p2> (0x600002170af0) after it has been removed from its context.
I think the solution here is to do some manual checking of the modelContext before saving. Would love to hear other's thoughts.
To reproduce:
In Xcode, create a new project with SwiftData storage
Add a new item in the preview — everything works fine so far
Enable CloudKit sync for the target (add iCloud capability, check CloudKit, add a container)
Go back to the preview and add a new item — Xcode will now freeze
As soon as you modify the SwiftData storage, the preview freezes and the Xcode app becomes extremely slow until you either refresh the preview or restart Xcode.
Hi,
I'm try to convert from CoreData to SwiftData.
Problem is that I'm using inheritance in CoreData.
So, I have a base class "animal" and "cat" and "bird" inherit from it.
I can have a array of type "animal" which contains both cats and dogs.
Now as I try to move to SwiftData I tried the following approach
protocol Animal {
var name: String { get set }
}
@Model
class Cat: Animal {
var name: String
var legs: Int
}
@Model
class Bird: Animal {
var name: String
var legs: Int
var wings: Int
}
@Model
class Enviroment {
//leads to error:
//Type 'any Animal' cannot conform to 'PersistentModel'
var animals: [any Animal]
}
So how to I get around of this? I would like to store multiple types of animals (classes that conform to protocol animal) … but how can I achieve that?
Thanks
Since the iOS 18 and Xcode 16, I've been getting some really strange SwiftData errors when passing @Model classes around.
The error I'm seeing is the following:
SwiftData/BackingData.swift:409: Fatal error: This model instance was destroyed by calling ModelContext.reset and is no longer usable.
PersistentIdentifier(id: SwiftData.PersistentIdentifier.ID(url: x-coredata://34EE9059-A7B5-4484-96A0-D10786AC9FB0/TestApp/p2), implementation: SwiftData.PersistentIdentifierImplementation)
The same issue also happens when I try to retrieve a model from the ModelContext using its PersistentIdentifier and try to do anything with it. I have no idea what could be causing this.
I'm guessing this is just a bug in the iOS 18 Beta, since I couldn't find a single discussion about this on Google, I figured I'd mention it.
if someone has a workaround or something, that would be much appreciated.
When using App Intents, I can edit already existing SwiftData items, but I cannot insert new ones. Below are the two app intents I've used, both function in their entirety other than the model context insertion at the end of the second one.
struct LinkViewedIntent: AppIntent {
static var title: LocalizedStringResource = "Mark Link Viewed"
@Parameter(title: "Link")
var link: LinkEntity?
init(link: Link) {
self.link = LinkEntity(link: link)
}
init() {}
func perform() async throws -> some IntentResult & ProvidesDialog {
let entities = try await LinkEntityQuery().suggestedEntities().filter({$0.viewed == false})
guard !entities.isEmpty else {
return .result(dialog: "There are no unviewed links to mark.")
}
var enteredLink: LinkEntity
if let link = link {
enteredLink = link
} else {
enteredLink = try await $link.requestDisambiguation(
among: LinkEntityQuery().suggestedEntities(),
dialog: "Which link would you like to mark viewed?"
)
}
let context = ModelContext(ConfigureModelContainer())
let links = try? context.fetch(FetchDescriptor<Link>())
guard let link = links?.filter({ $0.id == enteredLink.id }).first else {
return .result(dialog: "An Error Occured")
}
if link.viewed == true {
return .result(dialog: "Link is already viewed")
}
link.viewed = true
try context.save()
return .result(dialog: "Okay, \(enteredLink.name ?? enteredLink.link) has been marked as viewed.")
}
static var parameterSummary: some ParameterSummary {
Summary("Mark \(\.$link) as viewed.")
}
}
struct SaveLinkIntent: AppIntent {
static var title: LocalizedStringResource = "Save Link"
@Parameter(title: "URL")
var url: URL?
func perform() async throws -> some IntentResult & ProvidesDialog {
let modelContext = ModelContext(ConfigureModelContainer())
var fullurl: URL
if let url = url {
fullurl = url
} else {
fullurl = try await $url.requestValue()
}
print(fullurl.absoluteString)
guard let link = await makeLink(address: fullurl.absoluteString) else {
return .result(dialog: "")
}
modelContext.insert(link)
return .result(dialog: "I've added \(link.metadata?.title ?? link.address) to Memento")
}
}
CrashLog
Distributor ID: com.apple.AppStore
Hardware Model: iPhone15,3
Process: DeadLineTodo [5556]
Path: /private/var/containers/Bundle/Application/348CC8D5-05FD-41DF-93A3-C15562EF4AA8/DeadLineTodo.app/DeadLineTodo
Identifier: andy.DeadLineTodo
Version: 2.4.0 (3)
AppStoreTools: 15F31e
AppVariant: 1:iPhone15,3:17
Code Type: ARM-64 (Native)
Role: Foreground
Parent Process: launchd [1]
Coalition: andy.DeadLineTodo [2089]
Date/Time: 2024-06-08 19:13:53.6259 +0800
Launch Time: 2024-06-08 19:13:53.2839 +0800
OS Version: iPhone OS 17.5.1 (21F90)
Release Type: User
Baseband Version: 2.60.02
Report Version: 104
Exception Type: EXC_BREAKPOINT (SIGTRAP)
Exception Codes: 0x0000000000000001, 0x0000000195a2d8c0
Termination Reason: SIGNAL 5 Trace/BPT trap: 5
Terminating Process: exc handler [5556]
Triggered by Thread: 0
Thread 0 name:
Thread 0 Crashed:
0 libswiftCore.dylib 0x0000000195a2d8c0 _assertionFailure(_:_:file:line:flags:) + 264 (AssertCommon.swift:144)
1 DeadLineTodo 0x0000000100dde700 DeadLineTodoApp.init() + 1140 (DeadLineTodoApp.swift:46)
2 DeadLineTodo 0x0000000100ddef30 protocol witness for App.init() in conformance DeadLineTodoApp + 28 (<compiler-generated>:0)
3 SwiftUI 0x000000019b2c84c0 static App.main() + 116 (App.swift:114)
4 DeadLineTodo 0x0000000100ddeec4 static DeadLineTodoApp.$main() + 40 (<compiler-generated>:0)
5 DeadLineTodo 0x0000000100ddef5c main + 12 (DeadLineTodoApp.swift:32)
6 dyld 0x00000001ba7d1e4c start + 2240 (dyldMain.cpp:1298)
Thread 1:
0 libsystem_pthread.dylib 0x00000001f3fa40c4 start_wqthread + 0 (:-1)
Thread 2:
0 libsystem_pthread.dylib 0x00000001f3fa40c4 start_wqthread + 0 (:-1)
Thread 0 crashed with ARM Thread State (64-bit):
x0: 0x8000000100f01ad0 x1: 0x0000000000000000 x2: 0x0000000000000000 x3: 0x00000003019e9bc0
x4: 0x0000000000000000 x5: 0x000000016f16f3e0 x6: 0x000000000000002e x7: 0x0000000000000000
x8: 0x0000000000000100 x9: 0x00000000000000ff x10: 0x0000000000001b80 x11: 0x00000000f3444870
x12: 0x00000000000007fb x13: 0x00000000000007fd x14: 0x00000000f364506f x15: 0x000000000000006f
x16: 0x00000000f3444870 x17: 0x0000000000045000 x18: 0x0000000000000000 x19: 0x0000000100f01dba
x20: 0x8000000100f01ad0 x21: 0x0000000000000000 x22: 0x000000000000000b x23: 0x0000000000000022
x24: 0x000000000000002e x25: 0x0000000100f01ac0 x26: 0xd000000000000025 x27: 0x0000000000000000
x28: 0x0000000000000000 fp: 0x000000016f16f5c0 lr: 0x0000000195a2d8c0
sp: 0x000000016f16f4f0 pc: 0x0000000195a2d8c0 cpsr: 0x60001000
esr: 0xf2000001 (Breakpoint) brk 1
Binary Images:
0x100c90000 - 0x100f0ffff DeadLineTodo arm64 <c16650393d4537299a08b798b8227d31> /private/var/containers/Bundle/Application/348CC8D5-05FD-41DF-93A3-C15562EF4AA8/DeadLineTodo.app/DeadLineTodo
0x101214000 - 0x10121ffff libobjc-trampolines.dylib arm64e <2e2c05f8377a30899ad91926d284dd03> /private/preboot/Cryptexes/OS/usr/lib/libobjc-trampolines.dylib
0x1959f4000 - 0x195f43fff libswiftCore.dylib arm64e <d9ad5cc1ca2c3f0a8091652b0df56d14> /usr/lib/swift/libswiftCore.dylib
0x19af1c000 - 0x19ccbafff SwiftUI arm64e <c1325fda9da239d2ab83a338b4d8a884> /System/Library/Frameworks/SwiftUI.framework/SwiftUI
0x1ba795000 - 0x1ba821ef7 dyld arm64e <71846eacee653697bf7d790b6a07dcdb> /usr/lib/dyld
0x1f3fa3000 - 0x1f3fafff3 libsystem_pthread.dylib arm64e <1196b6c3333d3450818ff3663484b8eb> /usr/lib/system/libsystem_pthread.dylib
EOF
DeadLineTodoApp.swift
import SwiftUI
import SwiftData
typealias TodoData = TodoDataSchemaV8.TodoData
typealias UserSetting = TodoDataSchemaV8.UserSetting
enum TodoDataMigrationPlan: SchemaMigrationPlan {
static var schemas: [VersionedSchema.Type] {
[TodoDataSchemaV1.self, TodoDataSchemaV2.self, TodoDataSchemaV3.self, TodoDataSchemaV4.self, TodoDataSchemaV5.self, TodoDataSchemaV6.self, TodoDataSchemaV7.self, TodoDataSchemaV8.self]
}
static var stages: [MigrationStage]{
[migrationV1toV2, migrationV2toV3, migrationV3toV4, migrationV4toV5, migrationV5toV6, migrationV6toV7, migrationV7toV8]
}
static let migrationV1toV2 = MigrationStage.lightweight(fromVersion: TodoDataSchemaV1.self, toVersion: TodoDataSchemaV2.self)
static let migrationV2toV3 = MigrationStage.lightweight(fromVersion: TodoDataSchemaV2.self, toVersion: TodoDataSchemaV3.self)
static let migrationV3toV4 = MigrationStage.lightweight(fromVersion: TodoDataSchemaV3.self, toVersion: TodoDataSchemaV4.self)
static let migrationV4toV5 = MigrationStage.lightweight(fromVersion: TodoDataSchemaV4.self, toVersion: TodoDataSchemaV5.self)
static let migrationV5toV6 = MigrationStage.lightweight(fromVersion: TodoDataSchemaV5.self, toVersion: TodoDataSchemaV6.self)
static let migrationV6toV7 = MigrationStage.lightweight(fromVersion: TodoDataSchemaV6.self, toVersion: TodoDataSchemaV7.self)
static let migrationV7toV8 = MigrationStage.lightweight(fromVersion: TodoDataSchemaV7.self, toVersion: TodoDataSchemaV8.self)
}
@main
struct DeadLineTodoApp: App {
let container: ModelContainer
@StateObject var store = StoreKitManager()
@State var updated: Bool = false
init() {
do {
container = try ModelContainer(
for: TodoData.self, UserSetting.self,
migrationPlan: TodoDataMigrationPlan.self)
} catch {
print("初始化模型容器时发生错误:\(error)")
fatalError("Failed to initialize model container.")
}
}
var body: some Scene {
WindowGroup {
ContentView(updated: $updated)
.environmentObject(store)
}
.modelContainer(container)
}
}
Distributor ID: com.apple.AppStore
Hardware Model: iPhone15,3
Process: DeadLineTodo [5556]
Path: /private/var/containers/Bundle/Application/348CC8D5-05FD-41DF-93A3-C15562EF4AA8/DeadLineTodo.app/DeadLineTodo
Identifier: andy.DeadLineTodo
Version: 2.4.0 (3)
AppStoreTools: 15F31e
AppVariant: 1:iPhone15,3:17
Code Type: ARM-64 (Native)
Role: Foreground
Parent Process: launchd [1]
Coalition: andy.DeadLineTodo [2089]
Date/Time: 2024-06-08 19:13:53.6259 +0800
Launch Time: 2024-06-08 19:13:53.2839 +0800
OS Version: iPhone OS 17.5.1 (21F90)
Release Type: User
Baseband Version: 2.60.02
Report Version: 104
Exception Type: EXC_BREAKPOINT (SIGTRAP)
Exception Codes: 0x0000000000000001, 0x0000000195a2d8c0
Termination Reason: SIGNAL 5 Trace/BPT trap: 5
Terminating Process: exc handler [5556]
Triggered by Thread: 0
Thread 0 name:
Thread 0 Crashed:
0 libswiftCore.dylib 0x0000000195a2d8c0 _assertionFailure(_:_:file:line:flags:) + 264 (AssertCommon.swift:144)
1 DeadLineTodo 0x0000000100dde700 DeadLineTodoApp.init() + 1140 (DeadLineTodoApp.swift:46)
2 DeadLineTodo 0x0000000100ddef30 protocol witness for App.init() in conformance DeadLineTodoApp + 28 (<compiler-generated>:0)
3 SwiftUI 0x000000019b2c84c0 static App.main() + 116 (App.swift:114)
4 DeadLineTodo 0x0000000100ddeec4 static DeadLineTodoApp.$main() + 40 (<compiler-generated>:0)
5 DeadLineTodo 0x0000000100ddef5c main + 12 (DeadLineTodoApp.swift:32)
6 dyld 0x00000001ba7d1e4c start + 2240 (dyldMain.cpp:1298)
Thread 1:
0 libsystem_pthread.dylib 0x00000001f3fa40c4 start_wqthread + 0 (:-1)
Thread 2:
0 libsystem_pthread.dylib 0x00000001f3fa40c4 start_wqthread + 0 (:-1)
Thread 0 crashed with ARM Thread State (64-bit):
x0: 0x8000000100f01ad0 x1: 0x0000000000000000 x2: 0x0000000000000000 x3: 0x00000003019e9bc0
x4: 0x0000000000000000 x5: 0x000000016f16f3e0 x6: 0x000000000000002e x7: 0x0000000000000000
x8: 0x0000000000000100 x9: 0x00000000000000ff x10: 0x0000000000001b80 x11: 0x00000000f3444870
x12: 0x00000000000007fb x13: 0x00000000000007fd x14: 0x00000000f364506f x15: 0x000000000000006f
x16: 0x00000000f3444870 x17: 0x0000000000045000 x18: 0x0000000000000000 x19: 0x0000000100f01dba
x20: 0x8000000100f01ad0 x21: 0x0000000000000000 x22: 0x000000000000000b x23: 0x0000000000000022
x24: 0x000000000000002e x25: 0x0000000100f01ac0 x26: 0xd000000000000025 x27: 0x0000000000000000
x28: 0x0000000000000000 fp: 0x000000016f16f5c0 lr: 0x0000000195a2d8c0
sp: 0x000000016f16f4f0 pc: 0x0000000195a2d8c0 cpsr: 0x60001000
esr: 0xf2000001 (Breakpoint) brk 1
Binary Images:
0x100c90000 - 0x100f0ffff DeadLineTodo arm64 <c16650393d4537299a08b798b8227d31> /private/var/containers/Bundle/Application/348CC8D5-05FD-41DF-93A3-C15562EF4AA8/DeadLineTodo.app/DeadLineTodo
0x101214000 - 0x10121ffff libobjc-trampolines.dylib arm64e <2e2c05f8377a30899ad91926d284dd03> /private/preboot/Cryptexes/OS/usr/lib/libobjc-trampolines.dylib
0x1959f4000 - 0x195f43fff libswiftCore.dylib arm64e <d9ad5cc1ca2c3f0a8091652b0df56d14> /usr/lib/swift/libswiftCore.dylib
0x19af1c000 - 0x19ccbafff SwiftUI arm64e <c1325fda9da239d2ab83a338b4d8a884> /System/Library/Frameworks/SwiftUI.framework/SwiftUI
0x1ba795000 - 0x1ba821ef7 dyld arm64e <71846eacee653697bf7d790b6a07dcdb> /usr/lib/dyld
0x1f3fa3000 - 0x1f3fafff3 libsystem_pthread.dylib arm64e <1196b6c3333d3450818ff3663484b8eb> /usr/lib/system/libsystem_pthread.dylib
EOF
DeadLineTodoApp.swift
import SwiftData
typealias TodoData = TodoDataSchemaV8.TodoData
typealias UserSetting = TodoDataSchemaV8.UserSetting
enum TodoDataMigrationPlan: SchemaMigrationPlan {
static var schemas: [VersionedSchema.Type] {
[TodoDataSchemaV1.self, TodoDataSchemaV2.self, TodoDataSchemaV3.self, TodoDataSchemaV4.self, TodoDataSchemaV5.self, TodoDataSchemaV6.self, TodoDataSchemaV7.self, TodoDataSchemaV8.self]
}
static var stages: [MigrationStage]{
[migrationV1toV2, migrationV2toV3, migrationV3toV4, migrationV4toV5, migrationV5toV6, migrationV6toV7, migrationV7toV8]
}
static let migrationV1toV2 = MigrationStage.lightweight(fromVersion: TodoDataSchemaV1.self, toVersion: TodoDataSchemaV2.self)
static let migrationV2toV3 = MigrationStage.lightweight(fromVersion: TodoDataSchemaV2.self, toVersion: TodoDataSchemaV3.self)
static let migrationV3toV4 = MigrationStage.lightweight(fromVersion: TodoDataSchemaV3.self, toVersion: TodoDataSchemaV4.self)
static let migrationV4toV5 = MigrationStage.lightweight(fromVersion: TodoDataSchemaV4.self, toVersion: TodoDataSchemaV5.self)
static let migrationV5toV6 = MigrationStage.lightweight(fromVersion: TodoDataSchemaV5.self, toVersion: TodoDataSchemaV6.self)
static let migrationV6toV7 = MigrationStage.lightweight(fromVersion: TodoDataSchemaV6.self, toVersion: TodoDataSchemaV7.self)
static let migrationV7toV8 = MigrationStage.lightweight(fromVersion: TodoDataSchemaV7.self, toVersion: TodoDataSchemaV8.self)
}
@main
struct DeadLineTodoApp: App {
let container: ModelContainer
@StateObject var store = StoreKitManager()
@State var updated: Bool = false
init() {
do {
container = try ModelContainer(
for: TodoData.self, UserSetting.self,
migrationPlan: TodoDataMigrationPlan.self)
} catch {
fatalError("Failed to initialize model container.")
}
}
var body: some Scene {
WindowGroup {
ContentView(updated: $updated)
.environmentObject(store)
}
.modelContainer(container)
}
}
I'm experiencing a new error in SwiftData since updating to Xcode 16/iOS 17 DB1. When passing in a model (Student) to a view and then displaying an array of Points using ForEach, I get the following fatal error:
SwiftData/ModelCoders.swift:2438: Fatal error: Failed to locate relationship for StringCodingKey(stringValue: "group", intValue: nil) on Entity - name: Point
superentity:
subentities:
storedProperties:
CompositeAttribute - name: type, options: [], valueType: PointType, defaultValue: nil
Properties:
Attribute - name: type, options: [], valueType: String, defaultValue: nil, hashModifier: nil
Relationship - name: outcome, options: [], valueType: Outcome, destination: Outcome, inverseName: nil, inverseKeypath: nil
CompositeAttribute - name: proficiency, options: [], valueType: Proficiency, defaultValue: nil
Properties:
Attribute - name: proficiency, options: [], valueType: String, defaultValue: nil, hashModifier: nil
Attribute - name: date, options: [], valueType: Date, defaultValue: nil, hashModifier: nil
Attribute - name: note, options: [], valueType: String, defaultValue: nil, hashModifier: nil
Relationship - name: student, options: [], valueType: Optional<Student>, destination: Student, inverseName: points, inverseKeypath: Optional(\Student.points)
Attribute - name: group, options: [], valueType: Array<PersistentIdentifier>, defaultValue: [], hashModifier: nil
inheritedProperties:
uniquenessConstraints:
indices:
Xcode flags this line of the macro-generated getter of the outcome property on Point:
@storageRestrictions(accesses: _$backingData, initializes: _outcome)
init(initialValue) {
_$backingData.setValue(forKey: \.outcome, to: initialValue)
_outcome = _SwiftDataNoType()
}
get {
_$observationRegistrar.access(self, keyPath: \.outcome)
return self.getValue(forKey: \.outcome) // Fatal error: Failed to locate relationship for StringCodingKey...
}
set {
_$observationRegistrar.withMutation(of: self, keyPath: \.outcome) {
self.setValue(forKey: \.outcome, to: newValue)
}
}
This worked just fine in iOS 17. Here's a snippet of the Student implementation:
@Model
class Student: Identifiable, Comparable {
var name: String
var number: Int
@Relationship(deleteRule: .cascade, inverse: \Point.student) var points: [Point]
@Relationship(deleteRule: .cascade, inverse: \Mark.student) var marks: [Mark]
@Relationship(deleteRule: .nullify, inverse: \StudentGroup.students) var groups: [StudentGroup] = []
var archived: Bool
}
and the implementation of Point:
@Model
class Point: Identifiable, Comparable {
var student: Student?
var type: PointType
var outcome: Outcome
var proficiency: Proficiency
var group: [Student.ID] = []
var date: Date
var note: String
}
and finally the implementation for Outcome:
@Model
class Outcome: Identifiable, Comparable {
var name: String
var index: Int
var rubric: Rubric?
var proficiencies: [Proficiency]
}
I've tried adding a relationship in Outcome as an inverse of the outcomes property on Points (although this does not make sense in my implementation, which is why I initially did not set a relationship here) and the problem persisted.
Any ideas what this error means and how I might go about fixing it?
After watching the WWDC video on the new history tracking in SwiftData, I started to update my app with this functionality. Unfortunately it seems that the current API in the first beta of Xcode 16 is rather useless in regards to tombstone data.
The docs state that it would be possible to get the data from the tombstone by using a keyPath, there is no API for this however. The only thing I can do is iterate over the values (of type any) without any key information, so I do not know which data is what.
Am I missing something or did we get a half finished implementation? There also does not seem to be any info on this in the release notes.
I'm trying to insert values into my SwiftData container but it crashes on insert context.insert(fhirObject) and the only error I get from Xcode is:
@Transient
private var _hkID: _SwiftDataNoType?
// original-source-range: /Users/cyril/Documents/GitHub/MyApp/MyApp/HealthKit/FHIR/FHIRModels.swift:35:20-35:20
configured as follows:
import SwiftData
import SwiftUI
@main
struct MyApp: App {
var container: ModelContainer
init() {
do {
let config = ModelConfiguration(cloudKitDatabase: .private("iCloud.com.author.MyApp"))
container = try ModelContainer(for: FHIRObservation.self, configurations: config)
UserData.shared = UserData(modelContainer: container)
} catch {
fatalError("Failed to configure SwiftData container.")
}
}
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(UserData.shared)
}
.modelContainer(container)
}
}
My UserData and DataStore are configured as follows:
import SwiftUI
import SwiftData
import os
/// `FHIRDataStore` is an actor responsible for updating the SwiftData db as needed on the background thread.
private actor FHIRDataStore {
let logger = Logger(
subsystem:
"com.author.MyApp.FHIRDataStore",
category: "ModelIO")
private let container: ModelContainer
init(container: ModelContainer) {
self.container = container
}
func update(newObservations: [FHIRObservationWrapper], deletedObservations: [UUID]) async throws {
let context = ModelContext(container)
// [FHIRObservationWrapper] -> [FHIRObservation]
// let modelUpdates = newObservations.lazy.map { sample in
// FHIRObservation(hkID: sample.hkID, fhirID: sample.fhirID, name: sample.name, status: sample.status, code: sample.code, value: sample.value, range: sample.range, lastUpdated: sample.lastUpdated)
// }
do {
try context.transaction {
for sample in newObservations {
let fhirObject = FHIRObservation(hkID: sample.hkID, fhirID: sample.fhirID, name: sample.name, status: sample.status, code: sample.code, value: sample.value, range: sample.range, lastUpdated: sample.lastUpdated)
// App crashes here
context.insert(fhirObject)
}
// for obj in modelUpdates {
//
// }
// try context.delete(model: FHIRObservation.self, where: #Predicate { sample in
// deletedObservations.contains(sample.hkID!)
// })
// try context.save()
logger.debug("Database updated successfully with new and deleted observations.")
}
} catch {
logger.debug("Catch me bro: \(error.localizedDescription)")
}
}
}
@MainActor
public class UserData: ObservableObject {
let userDataLogger = Logger(
subsystem:
"com.author.MyApp.UserData",
category: "Model")
public static var shared: UserData!
// MARK: - Properties
public lazy var healthKitManager = HKManager(withModel: self)
let modelContainer: ModelContainer
private var store: FHIRDataStore
init(modelContainer: ModelContainer) {
self.modelContainer = modelContainer
self.store = FHIRDataStore(container: modelContainer)
}
// MARK: - Methods
func updateObservations(newObservations: [FHIRObservationWrapper], deletedObservations: [UUID]) {
Task {
do {
try await store.update(newObservations: newObservations, deletedObservations: deletedObservations)
userDataLogger.debug("Observations updated successfully.")
} catch {
userDataLogger.error("Failed to update observations: \(error.localizedDescription)")
}
}
}
}
My @Model is configured as follows:
public struct FHIRObservationWrapper: Sendable {
let hkID: UUID
let fhirID: String
var name: String
var status: String
var code: FHIRCodeableConcept
var value: FHIRLabValueType
var range: FHIRLabRange?
var lastUpdated: Date?
}
@Model
public final class FHIRObservation {
let hkID: UUID?
let fhirID: String?
@Attribute(.allowsCloudEncryption) var name: String?
@Attribute(.allowsCloudEncryption) var status: String?
@Attribute(.allowsCloudEncryption) var code: FHIRCodeableConcept?
@Attribute(.allowsCloudEncryption) var value: FHIRLabValueType?
@Attribute(.allowsCloudEncryption) var range: FHIRLabRange?
@Attribute(.allowsCloudEncryption) var lastUpdated: Date?
init(hkID: UUID?, fhirID: String?, name: String? = nil, status: String? = nil, code: FHIRCodeableConcept? = nil, value: FHIRLabValueType? = nil, range: FHIRLabRange? = nil, lastUpdated: Date? = nil) {
self.hkID = hkID
self.fhirID = fhirID
self.name = name
self.status = status
self.code = code
self.value = value
self.range = range
self.lastUpdated = lastUpdated
}
}
Any help would be greatly appreciated!