Post not yet marked as solved
Does SwiftData support UIImage as in CoreData specified here: https://www.swiftdevjournal.com/saving-images-in-core-data/ If it does, how to specify that in the @Model schema, especially using external storage to save the image in a separate file. Thanks.
Post not yet marked as solved
I have an App Group shared between my app and its widgets.
I have SwiftData's @Model, updated from the widget intent's perform() method and displayed on the app and the widget.
@MainActor
func perform() async throws -> some IntentResult {
let context = try ModelContainer(for: MyModel.self).mainContext
let myModel = try ModelContainer(for: MyModel.self).mainContext.fetch(
FetchDescriptor<MyModel>(predicate: #Predicate {
// The predicate is not the problem.
})
).first
myModel?.functionThatModifiesMyModel()
return .result()
}
Both the app and the widget SwiftUI views access to the model using Macros.
@Environment(\.modelContext) var context
@Query(sort: \.whatever) var myModel: [MyModel]
But the data is never correct in the app code (the widget's data is updated correctly using the intent).
Why doesn't the model make it to the app?
Post not yet marked as solved
Hi all,
I am trying to render my SwiftUI views that uses SwiftData classes using sample data using the approach shown in the example code of wwdc2023-10196:
@MainActor #Preview {
TripsWidgetEntryView()
.modelContainer(PreviewSampleData.container)
}
Unfortunately this seems no longer valid.
Indeed I get this error:
I then tried to remove the @MainActor as suggested, but the error in then moved to another level:
What do you suggest to be the best approach to have back my preview working?
I am using Xcode Beta 4 - 15A5195m
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
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
Post not yet marked as solved
PersistentModel is a protocol but would make more sense as a class that we then subclass. If all of the implementation was in a parent class of our model classes then there wouldn't be all the problems caused by requiring the use of the @Model macro, e.g. default property values not working, unable to subclass, overriding get/set not possible, conflict in property names...
Post not yet marked as solved
Problem
The following code doesn't work:
let predicate = #Predicate<Car> { car in
car.size == size //This doesn't work
}
Console Error
Query encountered an error: SwiftData.SwiftDataError(_error: SwiftData.SwiftDataError._Error.unsupportedPredicate)
Root cause
Size is an enum, #Predicate works with other type such as String however doesn't work with enum
Enum value is saved however is not filtered by #Predicate
Environment
Xcode: 15.0 (15A240d) - App Store
macOS: 14.0 (23A339) - Release Candidate
Steps to reproduce
Run the app on iOS 17 or macOS Sonoma
Press the Add button
Notice that the list remains empty
Expected behaviour
List should show the newly created small car
Actual behaviour
List remains empty inspite of successfully creating the small car.
Feedback
FB13194334
Code
Size
enum Size: String, Codable {
case small
case medium
case large
}
Car
import SwiftData
@Model
class Car {
let id: UUID
let name: String
let size: Size
init(
id: UUID,
name: String,
size: Size
) {
self.id = id
self.name = name
self.size = size
}
}
ContentView
struct ContentView: View {
var body: some View {
NavigationStack {
CarList(size: .small)
}
}
CarList
import SwiftUI
import SwiftData
struct CarList: View {
let size: Size
@Environment(\.modelContext)
private var modelContext
@Query
private var cars: [Car]
init(size: Size) {
self.size = size
let predicate = #Predicate<Car> { car in
car.size == size //This doesn't work
}
_cars = Query(filter: predicate, sort: \.name)
}
var body: some View {
List(cars) { car in
VStack(alignment: .leading) {
Text(car.name)
Text("\(car.size.rawValue)")
Text(car.id.uuidString)
.font(.footnote)
}
}
.toolbar {
Button("Add") {
createCar()
}
}
}
private func createCar() {
let name = "aaa"
let car = Car(
id: UUID(),
name: name,
size: size
)
modelContext.insert(car)
}
}
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.