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
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
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
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
}
}
Sorry this post is duplicate
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.
Xcode 15.2.
Brand new simulator set up, running 17.2.
Brand new AppleID, and have logged in and accepted terms.
Totally unable to login to iCloud on the Simulator to test iCloud syncing.
There are numerous threads dating back 6 years plus of people having issues logging in to iCloud on the Simulator.
Seems like it's still an issue. I have tried every solution. Existing AppleID. New AppleID. Logged into iCloud on Safari on Desktop and Simulator to check for unaccepted terms. Still get the commonly reported Sign-in page sitting spinning endlessly.
Checked Console for errors and only things that seem possibly related are:
com.apple.shortcuts CloudKitSync info 13:41:04.506714+0000 siriactionsd -[VCCKShortcutSyncCoordinator updateAccountStatusAndUserRecordID]_block_invoke Not fetching current user record ID because iCloud account is not available
Is it really still the case that logging in to iCloud on a Simulator, to test sign on or iCloud sync is still horribly broken, and has been for over 6 years?
when I run my project, I get this error and the simulator open app and show blank page.
I don't understand because I have to add some stores after I entry the app. but now I cannot entry it.
I used VersionedSchema and SchemaMigrationPlan
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
When I reference the ID of a SwiftData model entity (aka PersistentIdentifier) anywhere as a type (like @State var selection: Set<SomeEntity.ID> = Set<SomeEntity.ID>()) I now get the following error:
'ID' is inaccessible due to '@_spi' protection level
This never was a problem with CoreData and also not with SwiftData until the Xcode 15 RC.
Does anybody know, if this is a bug or intended behaviour?
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")
}
}
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)
}
}
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)
}
}
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?
When deleting the last added item from a list view in my app a bar chart in a different view crashes my app. If I delete any other item in the list view everything work as expected. I'm using SwiftData in my app.
Does anyone have any idea how I can prevent the app from crashing?
I filter the data in the init to only have the current days data
Chart View
struct ConsumedDrinkChartView: View {
@Environment(\.modelContext) var modelContext
let screenVerticalSizeClass = UIScreen.VerticalSizeClass
var compactScreen: Bool {
return screenVerticalSizeClass == "compact"
}
@State private var chartCalendarUnit: Calendar.Component = .hour
@State private var chartRange: ClosedRange<Date>
@State private var axisValueLabelFormat: Date.FormatStyle
@State private var axisValueLabelCount: Int
@State private var startDate: Date
@State private var endDate: Date
@State private var plotStartPadding: Double = 0
@State private var plotEndPadding: Double = 0
@Binding var selectedTimeFrame:String
@Query var consumedFluids: [ConsumedDrink]
let defaultVolume = DataStore.defaultVolume
init(selectedTimeFrame: Binding<String>, dateRange: ClosedRange<Date>) {
_selectedTimeFrame = selectedTimeFrame
_startDate = State(initialValue: Date().startOfDay)
_endDate = State(initialValue: Date().endOfDay)
let endDate = dateRange.upperBound
let startDate = dateRange.lowerBound
_consumedFluids = Query(filter: #Predicate {
$0.date > startDate && $0.date < endDate
}, sort: \ConsumedDrink.date)
_chartRange = State(initialValue: dateRange)
_axisValueLabelFormat = State(initialValue: .dateTime.hour(.conversationalDefaultDigits(amPM: .narrow)))
_axisValueLabelCount = State(initialValue: 2)
}
var body: some View {
Chart {
ForEach(consumedFluids) { consumedFluid in
BarMark(x: .value("Date", consumedFluid.date, unit: chartCalendarUnit),
y: .value("Fluid Ounces", consumedFluid.drink.amount))
}
.foregroundStyle(.pink)
}
.frame(height: 180)
.padding()
.chartXAxis {
AxisMarks(values: .stride(by: chartCalendarUnit, count: axisValueLabelCount,roundLowerBound: true, roundUpperBound: true)) { _ in
AxisGridLine()
AxisValueLabel(format: axisValueLabelFormat, centered: true)
}
}
.chartXScale(domain: chartRange, range: .plotDimension(startPadding: plotStartPadding, endPadding: plotEndPadding))
.background(RoundedRectangle(cornerRadius: 12).fill(Color(.secondarySystemBackground)))
.onChange(of: selectedTimeFrame) {
selectChartRange()
}
.onChange(of: consumedFluids) {
print("consumedFluids: \(consumedFluids.count)")
}
.onAppear {
selectChartRange()
}
}
func selectChartRange() {
plotStartPadding = 0
plotEndPadding = 0
switch selectedTimeFrame {
case "Day":
startDate = Date().startOfDay
endDate = Date().endOfDay
chartCalendarUnit = .hour
axisValueLabelCount = 2
axisValueLabelFormat = .dateTime.hour(.conversationalDefaultDigits(amPM: .narrow))
case "Week":
startDate = Date().add(days: -7)
chartCalendarUnit = .day
axisValueLabelCount = 1
axisValueLabelFormat = .dateTime.weekday()
case "Month":
startDate = Date().add(days: -30)
chartCalendarUnit = .day
axisValueLabelCount = 2
axisValueLabelFormat = .dateTime.day()
plotStartPadding = 10
plotEndPadding = 10
case "SixMonths":
let endOfMonth = Date().endOfMonth()
startDate = endOfMonth.add(months: -6)
chartCalendarUnit = .month
axisValueLabelCount = 1
axisValueLabelFormat = .dateTime.month()
plotStartPadding = 10
plotEndPadding = 32
case "Year":
let endOfMonth = Date().endOfMonth()
startDate = endOfMonth.add(months: -12)
chartCalendarUnit = .month
axisValueLabelCount = 1
axisValueLabelFormat = .dateTime.month(.narrow)
plotStartPadding = 15
plotEndPadding = 15
default:
chartCalendarUnit = .day
}
chartRange = startDate...endDate
}
}
List View
struct ConsumedDrinkListView: View {
@Environment(\.modelContext) var modelContext
@Query(sort: \ConsumedDrink.date) var dailyConsumedFluids: [ConsumedDrink]
@State private var showingAlert = false
@State private var alertMessage: String = ""
@State private var alertTitle: String = ""
var body: some View {
NavigationStack {
if dailyConsumedFluids.isEmpty {
ContentUnavailableView("No Consumed Drinks", systemImage: "mug.fill", description: Text("Drink some water and stay hydrated."))
} else {
List {
ForEach(dailyConsumedFluids, id: \.self) { consumedDrink in
NavigationLink {
EditConsumedDrinkView(consumedDrink: consumedDrink)
} label: {
ConsumedDrinkRowView(consumedDrink: consumedDrink)
}
.swipeActions{
Button("Delete", systemImage: "trash", role: .destructive) {
deleteConsumedDrink(consumedDrink: consumedDrink)
}
.tint(.red)
}
}
}
.listStyle(.plain)
.alert(isPresented: $showingAlert) {
Alert(title: Text(alertTitle),
message: Text(alertMessage),
dismissButton: .default(Text("OK"))
)
}
}
Text("")
.navigationTitle("Consumed Drinks")
.navigationBarTitleDisplayMode(.inline)
}
}
func deleteConsumedDrink(consumedDrink: ConsumedDrink) {
do {
if modelContext.hasChanges {
print("ConsumedDrinkListView.deleteConsumedDrink")
print("modelContext has Changes. Saving modelContext")
try modelContext.save()
}
try DataStore.deleteConsumedDrink(drink: consumedDrink, modelContext: modelContext)
} catch {
self.alertTitle = "Error deleting consumed drink - \(consumedDrink.drink.name)"
self.alertMessage = error.localizedDescription
self.showingAlert = true
}
}
}
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!
Hello
I have a swiftUI/swiftData document based app. In this I have created a singleton object using the folllowing in my ContentView struct:
@Query private var persistantStores:[PersistantStateManagerStorage]
@State private var stateManager: PersistantStateManagerStorage?
I then, call the following on the onAppear and onDisappear calls on the top level HStack{} item in my view
.onAppear(){
if let store = persistantStores.first
{
self.stateManager = store // data.first
} else
{
self.stateManager = PersistantStateManagerStorage()
modelContext.insert(stateManager!)
try? modelContext.save()
}
}.onDisappear(){
print("bye bye")
self.stateManager = nil
}
I then wrap my view inside a
if let stateManager = stateManager {}
block to unwrap the optional, and bind to values with a call such as
Stepper("Nudge Amount", value: Bindable(stateManager).nudgeAmount, in: 1...20)
I have to use Bindable(stateManager) rather than $stateManager as the $stateManager doesn't know its been unwrapped
All of this works fine until I close a document, at which point I get a crash with the message "SwiftData/BackingData.swift:124: Fatal error: Unable to get value - no backing Managed Object" which appears to happen when trying to access some of the properties of my persistantStore object (which has been retired)
I assume that my persistantStore object being an optional is part of the problem but I can't work out a better method of doing what I am trying to do
I have a document app built using SwiftData because frankly I'm too lazy to learn how to use FileDocument. The app's title is "Artsheets," and I'm using a document type that my app owns: com.wannafedor4.ArtsheetsDoc. The exported type identifier has these values:
Description: Artsheets Document
Identifier: com.wannafedor4.ArtsheetsDoc
Conforms to: com.apple.package
Reference URL: (none)
Extensions: artsheets
MIME Types: (none)
And the code:
ArtsheetsApp.swift
import SwiftUI
import SwiftData
@main
struct ArtsheetsApp: App {
var body: some Scene {
DocumentGroup(editing: Sheet.self, contentType: .package) {
EditorView()
}
}
}
Document.swift
import SwiftUI
import SwiftData
import UniformTypeIdentifiers
@Model
final class Sheet {
var titleKey: String
@Relationship(deleteRule: .cascade) var columns: [Column]
init(titleKey: String, columns: [Column]) {
self.titleKey = titleKey
self.columns = columns
}
}
@Model
final class Column: Identifiable {
var titlekey: String
var text: [String]
init(titlekey: String, text: [String]) {
self.titlekey = titlekey
self.text = text
}
}
extension UTType {
static var artsheetsDoc = UTType(exportedAs: "com.wannafedor4.artsheetsDoc")
}
I compiling for my iPhone 13 works, but then when creating a document I get this error:
Failed to create document. Error: Error Domain=com.apple.DocumentManager Code=2 "No location available to save “Untitled”." UserInfo={NSLocalizedDescription=No location available to save “Untitled”., NSLocalizedRecoverySuggestion=Enable at least one location to be able to save documents.}