Meet SwiftData

RSS for tag

Discuss the WWDC23 Session Meet SwiftData

View Session

Posts under wwdc2023-10187 tag

28 Posts
Sort by:
Post not yet marked as solved
4 Replies
1.4k Views
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?
Posted
by
Post not yet marked as solved
2 Replies
700 Views
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
Posted
by
Post not yet marked as solved
22 Replies
3.1k Views
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
Posted
by
Post not yet marked as solved
1 Replies
917 Views
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
Posted
by
Post not yet marked as solved
0 Replies
486 Views
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...
Posted
by
Post not yet marked as solved
3 Replies
1.1k Views
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) } }
Posted
by
Post not yet marked as solved
0 Replies
598 Views
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.
Posted
by