Build an app with SwiftData

RSS for tag

Discuss the WWDC23 Build an app with SwiftData

View Session

Posts under wwdc2023-10154 tag

62 Posts
Sort by:
Post not yet marked as solved
2 Replies
912 Views
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?
Posted
by meet__071.
Last updated
.
Post not yet marked as solved
6 Replies
3.0k Views
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
Posted
by jcfmunoz.
Last updated
.
Post marked as solved
5 Replies
3.3k Views
I did manage to save my Entities to CloudKit with SwiftData but the default database is the private database. I need to store some Entities in the private and other Entities in the public CloudKit database. How do I manage that with SwiftData? With CoreData I always used different configurations for both private and public and added the entities to one or the other.
Posted
by Ried.
Last updated
.
Post not yet marked as solved
4 Replies
1.4k Views
All demo code from Apple that I know lacks view models. Every time model data is directly injected into the view and even modified from the view via the new @Bindable macro. Is Apple not using ViewModels and therefore MVVM at all? I understand it might not really be required for the small demos, but it would still be helpful to understand, e. g. how the new @Model, @Observable, @Binding fit into the MVVM model.
Posted
by zumsel66.
Last updated
.
Post not yet marked as solved
6 Replies
4.1k Views
Hi, re: the SwiftData session "Create an app with SwifData" (https://developer.apple.com/videos/play/wwdc2023/10154) I noted the mention of generating sample preview data. In CoreData, I had a similar need and this was achieved by creating a shared in-memory context; fairly straight forward. The example given for SwiftData was decorated with @MainActor and then added to the target project, then in the #Preview closure, the modelContainer is amended to point to the preview data. Anyways, my problem is that I'm receiving an error when trying to render the preview in question: main actor-isolated let 'previewContainer' can not be referenced from a non-isolated context I suppose my issue is not having used the MainActor wrapper before and being unclear on what's possibly going wrong here (or if it's not just a "me" problem). Can anyone help?
Posted
by pjc83.
Last updated
.
Post marked as solved
3 Replies
1.3k Views
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
Posted Last updated
.
Post not yet marked as solved
2 Replies
850 Views
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
Posted
by milutz.
Last updated
.
Post not yet marked as solved
0 Replies
569 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 henningko.
Last updated
.
Post not yet marked as solved
9 Replies
973 Views
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
Posted
by LornaL.
Last updated
.
Post not yet marked as solved
1 Replies
657 Views
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?
Posted Last updated
.
Post not yet marked as solved
22 Replies
3k 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 dkk277.
Last updated
.
Post not yet marked as solved
1 Replies
497 Views
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.
Posted
by ellbosch.
Last updated
.
Post marked as solved
1 Replies
598 Views
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 } }
Posted
by jboersma.
Last updated
.
Post not yet marked as solved
4 Replies
3.4k Views
Okay, so I created a new Xcode project using SwiftData, and ticked the box for iCloud integration. I added a container on the web dashboard. Then I added “ = Date()” to the definition of Item.timestamp so that it has a default value. I added the container to my Xcode project.. Then I added this “let config” and “let container” and changed the “.modelContainer” like this: This will successfully add stuff to core data, which also appears in iCloud dashboard. BUT, if I delete the app and re-launch, I don’t see the existing iCloud data until the SECOND launch, even though the Xcode runtime log shows it fetched it. Do I need to do some magic to get it to refresh? Is the CloudKit subscription managed by SwiftData or do I need to do something for that? thanks!
Posted
by drewster.
Last updated
.
Post not yet marked as solved
4 Replies
1.7k Views
Hi, when inserting an entity with a relationship I get the following runtime error: Illegal attempt to establish a relationship 'group' between objects in different contexts [...]. The model looks like this: @Model class Person { var name: String @Relationship(.nullify, inverse: \Group.members) var group: Group init(name: String) { self.name = name } } @Model class Group { var name: String @Relationship(.cascade) public var members: [Person] init(name: String) { self.name = name } } It can be reproduced using this (contrived) bit of code: let group = Group(name: "Group A") ctx.insert(group) try! ctx.save() let descriptor = FetchDescriptor<Group>() let groups = try ctx.fetch(descriptor) XCTAssertFalse(groups.isEmpty) XCTAssertEqual(groups.count, 1) XCTAssertTrue(groups.first?.name == "Group A") let person = Person(name: "Willy") person.group = group ctx.insert(person) try ctx.save() (See also full test case below). Anybody experiencing similar issues? Bug or feature? Cheers, Michael Full test case: import SwiftData import SwiftUI import XCTest // MARK: - Person - @Model class Person { var name: String @Relationship(.nullify, inverse: \Group.members) var group: Group init(name: String) { self.name = name } } // MARK: - Group - @Model class Group { var name: String @Relationship(.cascade) public var members: [Person] init(name: String) { self.name = name } } // MARK: - SD_PrototypingTests - final class SD_PrototypingTests: XCTestCase { var container: ModelContainer! var ctx: ModelContext! override func setUpWithError() throws { let fullSchema = Schema([Person.self, Group.self,]) let dbCfg = ModelConfiguration(schema: fullSchema) container = try ModelContainer(for: fullSchema, dbCfg) ctx = ModelContext(container) _ = try ctx.delete(model: Group.self) _ = try ctx.delete(model: Person.self) } override func tearDownWithError() throws { guard let dbURL = container.configurations.first?.url else { XCTFail("Could not find db URL") return } do { try FileManager.default.removeItem(at: dbURL) } catch { XCTFail("Could not delete db: \(error)") } } func testRelAssignemnt_FB12363892() throws { let group = Group(name: "Group A") ctx.insert(group) try! ctx.save() let descriptor = FetchDescriptor<Group>() let groups = try ctx.fetch(descriptor) XCTAssertFalse(groups.isEmpty) XCTAssertEqual(groups.count, 1) XCTAssertTrue(groups.first?.name == "Group A") let person = Person(name: "Willy") person.group = group ctx.insert(person) try ctx.save() } }
Posted
by milutz.
Last updated
.
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 serg-ios.
Last updated
.
Post not yet marked as solved
3 Replies
1.6k Views
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) }
Posted Last updated
.
Post not yet marked as solved
3 Replies
1.2k Views
@Model class AModel { @Attribute(.unique) var id:String var date:Date var b:[BModel] init() { self.id = UUID().uuidString self.date = Date() self.b = [] } } @Model class BModel { @Attribute(.unique) var id:String var date:Date init() { self.id = UUID().uuidString self.date = Date() } } struct MainView: View { @Environment(\.modelContext) private var db @State private var a:AModel = AModel() var body: some View { VStack { } .onAppear { a.b.append(BModel()) print(a.b) } } } // CRASH : @Model class AModel { @Attribute(.unique) var id:String var date:Date var b:[BModel] /** Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) { get { _$observationRegistrar.access(self, keyPath: \.b) return self.getValue(for: \.b) } set { _$observationRegistrar.withMutation(of: self, keyPath: \.b) { self.setValue(for: \.b, to: newValue) } } } */ init() { self.id = UUID().uuidString self.date = Date() self.b = [] } } @Model class BModel { @Attribute(.unique) var id:String var date:Date init() { self.id = UUID().uuidString self.date = Date() } }
Posted Last updated
.