Build an app with SwiftData

RSS for tag

Discuss the WWDC23 Build an app with SwiftData

Posts under wwdc2023-10154 tag

43 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

SwiftData: Inserting two entities with same relationship target crashes
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.
0
0
618
Sep ’23
Help with "Trailing closure passed to parameter of type 'FormStyleConfiguration' that does not accept a closure."
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
9
0
1.1k
Sep ’23
SwiftData Macros don't seem to work
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?
2
1
734
Sep ’23
How to use the .onMove SwiftUI modifier to reorder SwiftData elements?
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) }
3
1
1.8k
Aug ’23
SwiftData does not work on a background Task even inside a custom ModelActor.
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
6
1
3.4k
Dec ’23
CoreData: error: CoreData: error: Row (pk = 1) for entity 'MergeRequest' is missing mandatory text data for property 'id'
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?
1
0
768
Aug ’23
Is it safe to mark SwiftData (@Model) classes as Sendable?
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
2
1
966
Aug ’23
Relationship Fault not happening in SwiftData
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.
0
0
642
Jul ’23
Can't query for the existence of an optional to-one relationship?
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
2
1
905
Sep ’23
SampleData on Previews @MainActor issue
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
4
0
713
Jul ’23
Previews are not building for the SwiftDataCardSample project.
I set my active schema to SwiftDataCardSampleEnd, open ContentView.swift, and bring up the Canvas. When I click the little refresh button I get the follow error from Canvas: == DATE: Friday, July 14, 2023 at 9:02:26 AM Eastern Daylight Time 2023-07-14T13:02:26Z == PREVIEW UPDATE ERROR: SchemeBuildError: Failed to build the scheme ”SwiftDataFlashCardSampleEnd” linker command failed with exit code 1 (use -v to see invocation) Link SwiftDataFlashCardSample (arm64): ld: Undefined symbols: unsafeMutableAddressor of self #1 : SwiftDataFlashCardSample.Card in SwiftDataFlashCardSample.Card.creationDate.init : Foundation.Date, referenced from: SwiftDataFlashCardSample.Card.creationDate.init : Foundation.Date in Card.o unsafeMutableAddressor of self #1 : SwiftDataFlashCardSample.Card in SwiftDataFlashCardSample.Card.back.init : Swift.String, referenced from: SwiftDataFlashCardSample.Card.back.init : Swift.String in Card.o unsafeMutableAddressor of self #1 : SwiftDataFlashCardSample.Card in SwiftDataFlashCardSample.Card.front.init : Swift.String, referenced from: SwiftDataFlashCardSample.Card.front.init : Swift.String in Card.o clang: error: linker command failed with exit code 1 (use -v to see invocation) I've made a similar preview in another project where I define a model and I try to use that model in a SwiftUI Canvas preview. I get a very similar error. Basically Canvas is saying it can't find the symbols for the properties on the type. Is there something I'm missing here? Some hidden build setting I need to flip. Or is this just busted?
4
0
701
Jul ’23
SwiftData - Multiple modelContexts in one modelContainer
In the WWDC presentations, it was mentioned that you could have multiple modelContexts within one modelContainer. Does anyone know of any examples of a project with multiple modelContexts? Specifically, I'm wondering how you distinguish between the two different modelContexts when doing things like @Query. I'd like to keep different sets of data in separate modelContexts and only Query the one that I want to pull from for a particular view. Thanks in advance!
2
2
1.4k
Jul ’23
Thread 1: Fatal error: expected attribute to be Codable
Not sure what I'm doing wrong here. I'm taking this opportunity to add persistence to an app that hadn't had it yet. I followed the session advice but I get this crash when running it: SwiftData/BackingData.swift:201: Fatal error: expected attribute to be Codable The crash is on this line: modelContext.insert(RentSplitDataModel()) The object being created and inserted there is simple and the compiler confirms it does conform to Codable: https://github.com/KyLeggiero/Rent-Split-for-iOS/blob/feature/MVP/Shared/Model/RentSplitDataModel.swift
7
1
1.4k
Sep ’23
Document and SwiftData ignore imported types
Hello there, I would like to bring attention to an issue I'm facing with SwiftData while attempting to create my own document type and a document-based app. It appears that there is a lack of support for imported types, and I'm unsure if this is a result of the beta version or an intentional omission. To reproduce the problem, please follow these steps: Create a document-based app with SwiftData enabled. Define your document type as "test" in the info.plist file. Include the "test" type in the list of exported type identifiers. Add a commonly used type such as "pdf" or "txt" to the list of imported type identifiers. Within the app's body, include a DocumentGroup with the content type set as "test." Currently, the app is capable of opening and creating new documents with the "test" type. However, I am unable to open common file types, such as images or text files. This limitation is a significant concern since the app often needs to handle these general file formats rather than being limited to its specific format. Thank you for your attention to this matter. I appreciate any assistance you can provide in resolving this issue. Best regards, Jeremy Vizzini
0
0
860
Jun ’23