Post not yet marked as solved
I have a Model Class Note:
@Model
class Note {
var id: UUID
var created: Date
var content: String
@Relationship(inverse: \Event.notes)
var events: [Event]?
init(_ content: String, created: Date = .now, events: [Event] = []) {
self.id = UUID()
self.created = created
self.content = content
self.events = events
}
}
And Event:
@Model
class Event: Hashable, Equatable {
var id: String
var name: String
var eventNotes: String?
@Relationship var notes: [Note]?
// @Transient does not publish (iOS bug?), use .ephemeral instead
@Attribute(.ephemeral) var isSelected: Bool = false
init(_ name: String = "Unnamed Event", calendarId: String, eventNotes: String) {
self.id = calendarId
self.name = name
self.eventNotes = eventNotes
}
init(from calendarEvent: EKEvent) {
self.id = calendarEvent.eventIdentifier
self.name = calendarEvent.title
self.eventNotes = calendarEvent.notes ?? ""
}
...
static func loadEvents(date: Date = Date()) -> [Event] {
...
}
}
I have the following View hierarchy
NoteInputView which has @State var events: [Event] = []
SelectEventButton which has @Binding var events: [Event] and calls Event.loadEvent() to retrieve list of events
SelectEventSheet which has @Binding var events: [Event] and lets the user toggle isSelected
GitHub Gist with all relevant files
Adding notes with same events crashes...
With this setup, I attempt so save new notes in NoteInputView by calling addNote:
func addNote() -> Note {
let selectedEvents = events.filter({ $0.isSelected })
let note = Note(newNoteContent, events: selectedEvents)
context.insert(note)
do {
try context.save()
} catch {
print(error)
}
return note
}
This works for the first note after opening the app, or if every subsequent note has a different event selected. However, storing a second note with the same event crashes with the following error:
"Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Illegal attempt to establish a relationship 'events' between objects in different contexts"
(complete error see here) The error occurs at context.insert, which doesn't throw.
If I force quit the app, and then add a note with the same events as an already persisted note, no error is thrown (until a I add another note with the same event without force-quitting).
... but not because one cannot refer to the same events twice
It's not a problem of referring to the same events, as the following code also works fine for multiple notes:
func addNote() -> Note {
// This works, despite notes also always referring to the same events
let note = Note(newNoteContent, events: Event.loadEvents())
context.insert(note)
do {
try context.save()
} catch {
print(error)
}
return note
}
.
... workaround? Manually adding events to the context before adding it to the notes
One workaround seems to be to add the events to the context before adding the note:
func addNote() -> Note {
let selectedEvents = events.filter({ $0.isSelected })
selectedEvents.forEach({context.insert($0)})
let note = Note(newNoteContent, events: events)
context.insert(note)
do {
try context.save()
} catch {
print(error)
}
return note
}
.
... but why?
While this works, I cannot quite make sense of this. It seems that passing events around between views may be the culprit, or that loadEvents is called in a child view.
Would love some advice, since this doesn't seem like intended behavior.
Post not yet marked as solved
Hello,
Apologies if I don't follow protocol. This is my first time asking a question.
I'm enjoying discovering Swift.
I'm getting tan error after Form { and wonder if you might know how to resolve it.
After Form {
I receive the following error: "Trailing closure passed to parameter of type 'FormStyleConfiguration' that does not accept a closure."
What am I doing wrong? Below is the entire RegisterView file.
Thank you in advance for any assistance.
How will I receive your response? I've not entered my email address anywhere?
Here at 17:39 shows what it should look like: https://www.youtube.com/watch?v=pAB1tMH6TFc
Lorna
import SwiftUI
struct RegisterView: View {
@StateObject var viewModel = RegisterView_ViewModel()
var body: some View {
VStack {
//Header
HeaderView(title: "Register",
subtitle: "Start organizing",
angle: -15,
background: .blue)
Form {
TextField("Full Name", text: $viewModel.name)
.textFieldStyle(DefaultTextFieldStyle())
.autocorrectionDisabled()
TextField("Email Address", text: $viewModel.email)
.textFieldStyle(DefaultTextFieldStyle())
.autocapitalization(.none)
.autocorrectionDisabled()
SecureField("Password", text: $viewModel.password)
.textFieldStyle(DefaultTextFieldStyle())
TLButton(
title: "Create Account",
background: .green
) {
viewModel.register()
}
.padding()
}
.offset(y: -50)
Spacer()
}
}
}
struct RegisterView_Previews: PreviewProvider {
static var previews: some View {
RegisterView()
}
}
Thank you in advance for your help.
Lorna
Post not yet marked as solved
I'm following the Build an app with SwiftData from WWDC 2023. I'm using the Xcode release candidate for Xcode 15. i'm running the Developer Beta for Sonoma. The first change was to import SwiftData, add the @Model macro to the Definition for the Card object and remove @Published from two variable in the definition. After doing this I get 5 errors: External macro implementation type 'SwiftDataMacros.PersistentModelMacro' could not be found for macro 'Model()'
The instructions continue to the CardEditorView and change the macro for var card to @Bindable with the error 'init(wrappedValue:)' is unavailable: The wrapped value must be an object that conforms to Observable
Then we move to the App main class where we add .modelContainer(for: Card.self) and get the error No exact matches in call to instance method 'modelContainer'
Any clue why this is happening?
In the code below a receive an error "A stored property cannot be named 'description'" . If I change the property "description" to "description1" the error is gone. I'am using Xcode 15b8. Anyone having the same problem
import Foundation
import SwiftData
@Model
class Category {
var name: String
var description: String
init(name: String, description: String) {
self.name = name
self.description = description
}
}
Post not yet marked as solved
I am new to SwiftData and I'm trying to use the .onMove modifier to rearrange "ChecklistItems"
List {
ForEach(items) { item in
ChecklistItemsListRowView(item: item, checklist: checklist)
.onTapGesture {
item.completed.toggle()
save()
} // onTapGesture
}
.onDelete(perform: { indexes in
for index in indexes {
modelContext.delete(checklist.items[index])
} // *for*
}) // onDelete
.onMove { IndexSet, int in
// TODO: Rearrange Elements
} // onMove
} // LIST
This is my ChecklistItem class:
@Model
final class ChecklistItem {
@Attribute(.unique)
var creationDate: Date
var name: String
var priority: Int
var notes: String
var completed: Bool
var checklist: Checklist?
init(creationDate: Date, name: String, priority: Int, notes: String, completed: Bool) {
self.creationDate = creationDate
self.name = name
self.priority = priority
self.notes = notes
self.completed = completed
}
}
extension ChecklistItem {
@Transient
static var preview = ChecklistItem(creationDate: Date(), name: "Item", priority: 2, notes: "This is a note.", completed: true)
}
Post not yet marked as solved
I'm wondering if the beta DocumentGroup API for SwiftData is working at all.
I've validated in multiple test projects that the linked API above fails. However I can resolve all issues by using a WindowGroup instead, where inside I'm querying SwiftData and able to get all data (even CloudKit persistence works).
Logs don't appear to contain useful information here.
Post not yet marked as solved
I have created an actor for the ModelContainer, in order to perform a data load when starting the app in the background. For this I have conformed to the ModelActor protocol and created the necessary elements, even preparing for test data.
Then I create a function of type async throws to perform the database loading processes and everything works fine, in that the data is loaded and when loaded it is displayed reactively.
actor Container: ModelActor {
nonisolated let modelContainer: ModelContainer
nonisolated let modelExecutor: ModelExecutor
static let modelContainer: ModelContainer = {
do {
return try ModelContainer(for: Empleados.self)
} catch {
fatalError()
}
}()
let context: ModelContext
init(container: ModelContainer = Container.modelContainer) {
self.modelContainer = container
let context = ModelContext(modelContainer)
self.modelExecutor = DefaultSerialModelExecutor(modelContext: context)
self.context = context
Task {
do {
try await loadData()
} catch {
print("Error en la carga \(error)")
}
}
}
}
The problem is that, in spite of doing the load inside a Task and that there is no problem, when starting the app it stops responding the UI while loading to the user interactions. Which gives me to understand that actually the task that should be in a background thread is running somehow over the MainActor.
As I have my own API that will provide the information to my app and refresh it at each startup or even send them in Batch when the internet connection is lost and comes back, I don't want the user to be continuously noticing that the app stops because it is performing a heavy process that is not really running in the background.
Tested and compiled on Xcode 15 beta 7.
I made a Feedback for this: FB13038621.
Thanks
Julio César
I'm converting my app to use SwiftData. I have a class called MergeRequest which everytime I insert it into the modelContext it fails with the following error:
CoreData: error: CoreData: error: Row (pk = 1) for entity 'MergeRequest' is missing mandatory text data for property 'id'
CoreData: error: CoreData: error: Row (pk = 2) for entity 'MergeRequest' is missing mandatory text data for property 'id'
(... repeated for each inserted item)
When I print the id before inserting the class does have a coredata generated id.
PersistentIdentifier(id: SwiftData.PersistentIdentifier.ID(url: x-coredata:///MergeRequest/t5B3316FC-DBE0-4440-88E5-8EDFBA7E856A3), implementation: SwiftData.PersistentIdentifierImplementation)
This is where I insert the model: https://github.com/StefKors/GitLab/blob/cb4c1ef6dec616d5ac146d712658496095c82243/Shared/UserInterface/UserInterface.swift#L137
And this is the full model class: https://github.com/StefKors/GitLab/blob/cb4c1ef6dec616d5ac146d712658496095c82243/Shared/UserInterface/SwiftData/MergeRequest.swift
What I don't get is why does this error happen while it does have an id. Is there some debugging I can do to get more information?
Post not yet marked as solved
I converted PhotosPickerItems into Data via loadTransferrable, and stored those into an array of data in @Model class, But whenever I try to retrieve it, processing time is very high. Has anybody come up wit an easy way to do this?
Post not yet marked as solved
The Sendable documentation says we can mark reference types as Sendable if they "internally manage access to their state."
Adding Sendable conformance to my SwiftData classes silences warnings such as the following: "Non-sendable type '[Item]' returned by implicitly asynchronous call to nonisolated function cannot cross actor boundary"
@Model final class Item: Sendable {
var sampleProperty = ""
}
My understanding is that the compiler would complain if adding explicit Sendable conformance to a swift data model was breaking concurrency rules, but I wanted to check with the community to see what everyone thinks.
Best,
Taylor
I tried coding along with the WWDC23 'Dive Deeper into SwiftData' video but can't get the sample code to compile.
For example the Card class fails with lots of errors associated with @Model. The first of these is: Type 'Card' does not conform to protocol 'PersistentModel'
import SwiftUI
import SwiftData
@Model
final class Card {
var front: String
var back: String
var creationDate: Date
init(front: String, back: String, creationDate: Date = .now) {
self.front = front
self.back = back
self.creationDate = creationDate
}
}
On the other hand the following stand alone code (in it's own project) compiles without error. So I am confused and a little fed up with Apple publishing sample code that doesn't compile.
import SwiftData
@Model
final class Card {
var front: String
var back: String
var creationDate: Date
init(front: String, back: String, creationDate: Date = .now) {
self.front = front
self.back = back
self.creationDate = creationDate
}
}
struct ContentView: View {
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, world!")
}
.padding()
}
}
#Preview {
ContentView()
}
Post not yet marked as solved
I just installed Xcode beta 6 and tried compiling the SwiftData sample app. It fails with a couple of dozen compile errors. Clearly this must have worked for WWDC23 so what's gone wrong?
The following says type 'Card' does not conform to protocol 'PersistentModel'
@Model
final class Card: PersistentModel {
This seems pretty basic.
Any suggestions
Post not yet marked as solved
There is a new Relationship macro in Xcode Beta 6. The macro includes two new arguments: minimumModelCount and maximumModelCount. I wonder if anyone knows what these values are for and if there is another change under the hood.
Relationship(
_ options: PropertyOptions...,
deleteRule: Schema.Relationship.DeleteRule = .nullify,
minimumModelCount: Int? = 0,
maximumModelCount: Int? = 0,
originalName: String? = nil,
inverse: AnyKeyPath? = nil,
hashModifier: String? = nil
)
The compiler is raising the following error for @Relationship(.cascade, inverse: ...) with the message Type 'PropertyOptions' has no member 'cascade' Is there a replacement for this property option, or is the cascade behaviour implied internally by default?
Post not yet marked as solved
It's been frustrating to solve this error. My iOS device and Xcode are fully updated. I can easily run app on simulator, but issue happens on my iPhone.
dyld[23479]: Symbol not found: _$s9SwiftData12ModelContextC6insert6objectyx_tAA010PersistentC0RzlFTj
Referenced from: <6FC773BB-E68B-35A9-B334-3FFC8B951A4E> Expected in: /System/Library/Frameworks/SwiftData.framework/SwiftData
Post not yet marked as solved
When running a macOS app on Xcode 15 Beta 5 (15A5209g), I get a Symbol Not Found error.
Problem: App will not run. Error received. Symbol Not Found: SwiftData Default Backing For AC
Environment: Version 15.0 beta 5 (15A5209g), macOS 14.0 Beta (23A5257q)
App: macOS
SwiftData Model
@Model
class Audit {
init() { }
}
Error:
dyld[875]: Symbol not found: _$s9SwiftData014DefaultBackingB0C3forACyxGxm_tcfC
Referenced from: <75DF3350-4DD5-3AF4-80DA-B17B0EDD26C2> /Users/dking/Library/Developer/Xcode/DerivedData/{redacted}-bigzojxvffztaaaepdczriowvoie/Build/Products/Debug/{redacted}.app/Contents/MacOS/{redacted}
Expected in: /System/Library/Frameworks/SwiftData.framework/Versions/A/SwiftData
Post not yet marked as solved
I have two models a Person and a Possession
the Person model has a one to many relationship to the Possession model.
meaning each possession can only have one person but a person can have multiple possessions.
I have set my model like the following
Person:
@Model
class Person {
@Attribute(.unique)
let personID: String
@Relationship(.cascade, inverse: \Possession.person)
var possetions: [Possession]?
init(id: String, possessions: [Possession]) {
self.personID = id
self.possetions = possessions
}
}
Possession:
@Model
class Possession {
@Attribute(.unique)
let id: String
let name: String?
var person: Person?
init(id: String, name: String, person: Person) {
self.id = id
self.name = name
self.person = person
}
}
If i set a breakpoint i see that all the posessions are loaded into the memory this is something i do not want to happen.
In Core Data we get a relationship fault however, i am not seeing the same behavior in SwiftData.
here's how my view is implemented
struct ContentView: View {
@Environment(\.modelContext) private var modelContext
@EnvironmentObject private var navigationStore: NavigationStore
@Query() private var people: [Person]
var body: some View {
List {
ForEach(people) { person in
NavigationLink(value: person) {
VStack {
Text(person.personID)
}
}
.swipeActions {
Button("Delete") {
modelContext.delete(person)
}
}
}
}
.toolbar(content: {
Button("Add") {
let newPErson = Person(id: UUID().uuidString, possessions: [])
modelContext.insert(newPErson)
do {
try modelContext.save()
} catch {
assertionFailure("\(error)")
}
}
})
.navigationDestination(for: Person.self) { person in
Text("hello")
}
}
}
at the launch i do not want posessions to be loaded into the memory. I want them loaded when they are being used.
Post not yet marked as solved
I am getting the following error on this line of code
@Query(sort: \.id, order: .reverse) private var artList: [ArtInventory]
Cannot infer key path type from context; consider explicitly specifying a root type
So, I select fix and then the line of code then look like this
@Query(sort: \<#Root#>.id, order: .reverse) private var artList: [ArtInventory]
with this error
Invalid component of Swift key path
Some seems to have changed with the @Query macro in beta 5, which now needs a root type, but not sure how to proceed.
Any ideas how to fix?
Post not yet marked as solved
Hi,
say in my model I have members and each member optionally can have a relationship to a Club. So the relationship in the Member entity would be modelled like so:
@Relationship(.nullify, inverse: \Club.members) var club: Club?
Now I would like to fetch al Members with no Club relationship. I would assume that this would work with a predicate like this:
let noClubPred = #Predicate<Member> { member in
member.club == nil
}
Unfortunately this gives me the following error when compiling:
Generic parameter 'RHS' could not be inferred.
Has anybody an idea how to phrase this predicate correctly, or is this a beta issue and it should actually work?
Thank you!
Cheers, Michael
Post not yet marked as solved
Anyone know the SwiftData equivalet of the CoreData lifecycle methods. and how do we override them or do something similar? eg:
awakeFromInsert()
willSave()
didSave()
willTurnIntoFault()
prepareForDeletion()