SwiftData

RSS for tag

SwiftData is an all-new framework for managing data within your apps. Models are described using regular Swift code, without the need for custom editors.

Posts under SwiftData tag

200 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

Dependent models preview container error
I have a set of cascading dependent models. I want to create a preview container that adds them all to a preview container. I have created a model container which loads a recipe of my choice in sequentialy so the instantiation works. I noticed that everything loads but only 1 RecipeStep will ever be added. No matter how I do it, only one is added (randomly). What is the best practice for creating a swiftdata preview with dependent models? How can I put them in a struct / class for easy access? I tried making a class that initialized the whole swiftdata object however the preview crashes when using this. Note: I know one solution is that I could make child to parent fields optional, but I don't want to do that since I need them required. @Model class CocktailRecipe { @Attribute(.unique) var id: UUID @Attribute(.unique) var name: String var info: String? var menu: CocktailMenu? @Relationship(deleteRule: .cascade, inverse: \Ingredient.recipe) var ingredients: [Ingredient] @Relationship(deleteRule: .cascade, inverse: \RecipeSection.recipe) var sections: [RecipeSection] var created_at: Date init(name: String, info: String? = nil, menu: CocktailMenu? = nil, sections: [RecipeSection] = [], ingredients: [Ingredient] = []) { self.name = name self.info = info self.menu = menu self.sections = sections self.ingredients = ingredients self.created_at = Date() self.id = UUID() } } @Model class Ingredient { @Attribute(.unique) var id: UUID @Attribute(.unique) var name: String var quantity: Float? var units: IngredientUnitType var type: IngredientType var recipe: CocktailRecipe var created_at: Date init(name: String, quantity: Float? = nil, units: IngredientUnitType, type: IngredientType, recipe: CocktailRecipe) { self.name = name self.quantity = quantity self.units = units self.type = type self.recipe = recipe self.created_at = Date() self.id = UUID() } } @Model class RecipeSection { @Attribute(.unique) var id: UUID @Attribute(.unique) var title: String? @Attribute(.unique) var index: Int @Relationship(deleteRule: .cascade, inverse: \RecipeStep.section) var steps: [RecipeStep] var recipe: CocktailRecipe var created_at: Date init(title: String? = nil, recipe: CocktailRecipe, steps: [RecipeStep] = []) { self.title = title self.recipe = recipe self.index = recipe.sections.count + 1 self.steps = steps self.created_at = Date() self.id = UUID() } } @Model class RecipeStep { @Attribute(.unique) var id: UUID @Attribute(.unique) var instruction: String @Attribute(.unique) var index: Int var section: RecipeSection var created_at: Date init(instruction: String, section: RecipeSection) { self.instruction = instruction self.section = section self.index = section.steps.count + 1 self.created_at = Date() self.id = UUID() } } let cocktailPreviewContainer: ModelContainer = { do { let container = try ModelContainer( for: CocktailMenu.self, CocktailRecipe.self, Ingredient.self, RecipeSection.self, RecipeStep.self, /*Bottle.self, Bar.self, */ configurations: ModelConfiguration(isStoredInMemoryOnly: true) ) let modelContext = container.mainContext let spicyMargarita = CocktailRecipe(name: "Spicy Margarita") modelContext.insert(spicyMargarita) // Initialize ingredients let spicyMargaritaIngredients = [ Ingredient(name: "Tequila", quantity: 2, units: .ounces, type: .tequila, recipe: spicyMargarita), Ingredient(name: "Lime Juice", quantity: 1, units: .ounces, type: .mixer, recipe: spicyMargarita), Ingredient(name: "Agave Syrup", quantity: 0.5, units: .ounces, type: .mixer, recipe: spicyMargarita), // Ingredient(name: "Jalapeno", quantity: 3, units: .slices, type: .garnish, recipe: spicyMargarita) ] for ingredient in spicyMargaritaIngredients { modelContext.insert(ingredient) } try? modelContext.save() // Initialize sections and steps let preparationSection = RecipeSection(title: "title here", recipe: spicyMargarita) modelContext.insert(preparationSection) try? modelContext.save() let step1 = RecipeStep(instruction: "Muddle the jalapeno slices in the shaker.", section: preparationSection) modelContext.insert(step1) let step2 = RecipeStep(instruction: "Add tequila, lime juice, and agave syrup to shaker with ice.", section: preparationSection) modelContext.insert(step2) let step3 = RecipeStep(instruction: "Shake well.", section: preparationSection) modelContext.insert(step3) let step4 = RecipeStep(instruction: "Strain into a chilled glass.", section: preparationSection) modelContext.insert(step4) return container } catch { fatalError("Failed to create container") } }() var spicyMargarita: CocktailRecipe init() { // Initialize spicyMargarita recipe spicyMargarita = CocktailRecipe(name: "Spicy Margarita") // Initialize ingredients let tequila = Ingredient(name: "Tequila", quantity: 2, units: .ounces, type: .tequila, recipe: spicyMargarita) let limeJuice = Ingredient(name: "Lime Juice", quantity: 1, units: .ounces, type: .mixer, recipe: spicyMargarita) let agaveSyrup = Ingredient(name: "Agave Syrup", quantity: 0.5, units: .ounces, type: .mixer, recipe: spicyMargarita) let jalapeno = Ingredient(name: "Jalapeno", quantity: 3, units: .slices, type: .garnish, recipe: spicyMargarita) // Initialize sections and steps let preparationSection = RecipeSection(recipe: spicyMargarita) let preparationSteps = [ RecipeStep(instruction: "Muddle the jalapeno slices in the shaker.", section: preparationSection), RecipeStep(instruction: "Add tequila, lime juice, and agave syrup to shaker with ice.", section: preparationSection), RecipeStep(instruction: "Shake well.", section: preparationSection), RecipeStep(instruction: "Strain into a chilled glass.", section: preparationSection) ] // WHEN THE BELOW IS COMMENTED OUT, no errors, but have many missing objects. spicyMargarita.ingredients.append(contentsOf: [tequila, limeJuice, agaveSyrup, jalapeno]) spicyMargarita.sections.append(preparationSection) preparationSection.steps.append(contentsOf: preparationSteps)
0
0
144
Apr ’24
SwiftData, Core Data, and initializing CloudKit development Schema
I recently discovered the new documentation for enabling CloudKit sync with SwiftData. A key step I was missing in my previous setup was this step: Initialize the CloudKit development schema. When I run this though, I get Core Data errors in my log... CoreData: Unsupported attribute type I've noticed that it seems to be preventing adding fields for my model properties that are Codable structs. I've been able to add Codable structs to my SwiftData models synced with CloudKit before. But using Core Data to initialize the CloudKit schema like the documentation suggests just doesn't work. Is there some other way around this? I'm about to just give up on CloudKit sync altogether. I need this to work because I'm trying to add some new fields and populate the fields with data based on existing data during the migration, but this seems to be preventing migration completely. If I don't initialize the schema, I get different errors and the ModelContainer won't initialize at all.
2
1
431
Apr ’24
Slightly weird SwiftData issue relating to background context inserts on a unrelated line of code
Hello. I had an issue that I was able to resolve, but I'd like to see if anyone might know why it happened in the first place. Essentially, I have a SwiftData model called Vehicle. This model has an array of Mileage, another SwiftData model. Vehicle has an init that accepts a Vehicle as a parameter and then matches it with that one. init(from vehicle: Vehicle) { self.id = vehicle.id self.timestamp = vehicle.timestamp self.year = vehicle.year self.make = vehicle.make self.model = vehicle.model self.trim = vehicle.trim self.mileage = vehicle.mileage self.nickname = vehicle.nickname } Previously, I had the line self.mileageHistory = vehicle.mileageHistory in this init. However, that line caused a duplicate Vehicle model to be created and inserted into the context. I could tell because I had a List that was displaying all of the created Vehicle models from a Query. It all stems from a view that is being displayed in a sheet. This view accepts a vehicle parameter called copy. .sheet(isPresented: $edit, content: { VehicleEditView(vehicle: vehicle, copy: Vehicle(from: vehicle)) }) In a way I can understand why it's happening because a new Vehicle model is being created. But I don't understand why it only happens when the mileageHistory variables are set equal to each other. I removed that line and it doesn't do it anymore. I had to workaround it by setting the mileageHistory elsewhere. Does anyone know why this might be happening?
2
0
355
Apr ’24
App freezes when tapping a navigation link
I have two main models, House and Expense. On the home page I show a list of the three most recent expenses using the following query: var descriptor = FetchDescriptor<Expense>(predicate: #Predicate { $0.houseID == house.id }, sortBy: [SortDescriptor(\.date, order: .reverse)]) descriptor.fetchLimit = 3 _recentExpenses = Query(descriptor) I have a NavigationLink that takes you to the full list of expenses: NavigationLink { ExpenseListView(house: house) } label: { Text("See all") } On this page I have a query similar to the previous one, without the fetch limit: let descriptor = FetchDescriptor<Expense>( predicate: #Predicate { $0.houseID == house.id} ) _expenses = Query(descriptor) The problem is that when I click on the navigation link to go to the expenses page, the app freezes. I tried passing the expenses array to the second page instead of invoking another query, but this way the view doesn't update when I update the expenses. Is there a way to solve this problem? Or a way to pass a Binding of the fetched results?
4
1
673
Apr ’24
SwiftData - Insert and delete
Hi, I started a new project selecting SwiftData as db by default. I created my models as default. @Model class Trip { var id: UUID public private(set) var Name: String public private(set) var Members: [Member] public private(set) var Buys: [Buy] public func removeBuy(indexBuyToRemove: Int) { self.Buys.remove(at: indexBuyToRemove) } } @Model class Member: Identifiable, Equatable { var id: UUID public private(set) var Name: String } @Model class Buy: Identifiable, Equatable { var id: UUID public private(set) var Author: Member public private(set) var Ammount: Double public private(set) var Title: String } I initialize my trips as this in my ContentView @Query public var tripsList: [Trip] And then pass this list in every other view. I also have a ModelContext as default, passed like this in the @Main @main struct MainApp: App { var sharedModelContainer: ModelContainer = { let schema = Schema([ Member.self, Buy.self, Trip.self ]) let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false) do { return try ModelContainer(for: schema, configurations: [modelConfiguration]) } catch { fatalError("Could not create ModelContainer: \(error)") } }() var body: some Scene { WindowGroup { ContentView() .preferredColorScheme(.dark) } .modelContainer(sharedModelContainer) } } And defining in the other views like this @Environment(\.modelContext) var modelContext Now. For the problem of consistency. Whenever I add a new Trip I do this or delete (as .onDelete in the List) public func addTrip(Trip: Trip) { modelContext.insert(Trip) } private func deleteItems(offsets: IndexSet) { withAnimation { for index in offsets { modelContext.delete(tripsList[index]) } } } And everything works fine. The problem starts when I try to delete a Buy element of the Trip.Buys: [Buy]. I do like this: private func deleteItems(offsets: IndexSet) { withAnimation { for index in offsets { let buyToRemove = trip.Buys[index] trip.removeBuy(indexBuyToRemove: index) do { try modelContext.save() } catch {} } } } The delete is not consistent. What am I missing? What am I doing wrong? Thank you for your help
0
0
254
Apr ’24
How to save a singleton using SwiftData?
I am persisting a tree data structure Node using SwiftData with CloudKit enabled. I understand how to manage my NonSingleton models in SwiftUI. However, when a user first launches my app a Node model instance needs to be created that is separate from any NonSingleton model. So I think a Singleton class is appropriate but I don't know how to persist it? @Model final class Node { var parent: Node? @Relationship(deleteRule: .cascade, inverse: \Node.parent) var children = [Node]() // ... } @Model final class NonSingleton { @Relationship(deleteRule: .cascade) var node: Node // ... } @Model // ? final class Singleton { static var node = Node() private init() {} }
1
0
438
Apr ’24
.dropDestination on TableRow updated recently?
Using: @Model class Object: Observable, Transferable TableRow(object) .draggable(object) .dropDestination(for: Object.self) { _ in return } (with or without the "return") is the only .dropDestination syntax that compiles for me. Specifying the single return argument as (droppedItems:[Account]) is tolerated Using "return true" or expecting two returned items does not compile. I suspect the single returned item is the dropped items array, seems fair as "location" is not needed when using a TableRow. This is different behavior than all the docs and examples I've seen. My Object is Codable and Transferable. A row can be dragged and a destination row highlights on hover-with-payload, but on drop I get a spinning wheel even though I've not specified any action yet. The action closure is not entered, even a simple print() statement is not reached. I'd appreciate any thoughts on what might be the problem here. Debugger tips welcome, too. swift-driver version: 1.90.11.1 Apple Swift version 5.10 (swiftlang-5.10.0.13 clang-1500.3.9.4) Target: arm64-apple-macosx14.0
1
0
235
Apr ’24
SwiftData deleteRules & uniqueness
Hello everyone, How do I need to handle the delete with the relationship deny? When I delete a model that still has a reference to another model, it deletes it from the UI. But when I re-run the simulator, it's back again. Does someone have a hint for me? How is it possible to ensure the uniqueness of the entries? Because I saw that the Attribute unique can't be used with CloudKit.
1
0
392
Apr ’24
SwiftData - Load the data into Apps
I am developing "Tasty Recipes" app. I want to load all data related to this app such "Recipe Category", "Recipes List", "Recipes Inscredient", "Preparation Methods" and so on. How can I load and store all data using SwiftData. User is going to use these data. They will update few things like "Favourite Recipes", "Rating". How can I do this.
2
0
437
Apr ’24
Persisting SwiftData After App Deletion
Hello, I've encountered an issue where SwiftData remains in the /Users/(username)/Library/Containers/MyApp directory even after my MacOS app has been deleted. This behavior is not what I expected. Has anyone else faced this issue? Also, I'm wondering if there is a delay in the deletion process that might account for this. is there a known time lag before everything is cleared out? Thanks.
1
0
400
Apr ’24
How to do Add, View, Edit (with Cancel and Done)
I'm not sure how to pull off a viewer/editor with SwiftData + SwiftUI that supports Cancel I want the user to be able to: Tap + to bring up a sheet/form to create a new Item. The navigation bar shows Cancel and Create. Create is only enabled when the fields are mostly valid. Tap Create to do a deeper validation and add. Tap Cancel to not make any changes. Tap an item to view it. Tap Edit when viewing to edit. The navigation bar shows Cancel and Done. Done is only enabled when the fields are mostly valid. Tap Done to do a deeper validation and save changes. Tap Cancel to not make any changes. I think is a fairly common pattern. It's used by Contacts, for instance. I've got parts of this working. Creating is easy: I just insert it only after the user taps Create and it's validated. But Edit/Cancel/Done seems harder. If I disable autosaving the changes to the model, the changes are applied to other parts of SwiftUI immediately. And I haven't figured out how to cancel the changes. Should I be operating on a copy of the object instead? How do I copy it in a way that doesn't impact SwiftData? I'm happy to take any tips you might have, but if you want to look at the code and suggest something that way I put my test case up here: https://github.com/tewha/ItemEditor My hope is I can get this sample working, get the changes into my app, and keep the sample up for others to discover (though I feel this would also be a great concept for sample code).
1
0
303
Apr ’24
SwiftData data propagation
My app application uses pure Swift, SwiftUI, & SwiftData. One view contains a quiz. After a user completes a quiz I would like to display the results in another separate view. My specific problem is passing data to sibling views (from origin view to destination view). If anyone could help I would appreciate it. I’m using @Model macro above my class .modelContainer for designing/ designating the container @Envioronment variable to insert the data into the context of the origin view. Add same data (quiz result) to destination view.
1
0
345
Apr ’24
Bitwise operators in predicate with SwiftData
I have a model class with various status values that I would like to store in a single 64 bits integer. For example one bit for this boolean flag, 4 bits for that lookup value and so on. I tried to create a predicate containing bitwise operators to query specific bits but that seems impossible, no way no compile it. is there a way I am no aware of to accomplish this, some workaround or is that planned to be possible in future Swiftdata release? that would be a shame having to store a few status values of 4 or less bits each in different 64bits values, what a waste! Thanks Tof
0
1
227
Apr ’24
How do you configure a document-based SwiftUI multi-platform app to be able to import .log files?
In a new document-based UIKit app, specifying in the Info.plist an import type identifier of public.log that conforms to public.content, public.data, public.item accomplishes this. In a new document-based SwiftUI multi-platform app, doing the same crashed at the DocumentGroup initializer with the error _SwiftData_SwiftUI/Documents.swift:91: Fatal error: The document type is public.log which does not conform to com.apple.package. This initializer expects the document type to be a package.
1
0
376
Mar ’24
SwiftData data created for previewing crashes the app sometimes
I am creating an app for organising books using SwiftUI and SwiftData. Adapting the code from Building a document-based app using SwiftData, I created the following model container for use in SwiftUI views (or the simulator). @MainActor let previewData: ModelContainer = { do { let bookSchema = Schema([Book.self]) let configuration = ModelConfiguration(isStoredInMemoryOnly: true) let container = try ModelContainer( for: bookSchema, configurations: configuration) let modelContext = container.mainContext if try modelContext.fetch(FetchDescriptor<Book>()).isEmpty { var books = [ Book(name: "A book", year: 2024), Book(name: "On Film Making", author: "Alexandar Mackendrick", year: 2005, isbn: try! validateISBN(isbn: "9780571211258")) ] for book in books { modelContext.insert(book) print("Inserted book") } } return container } catch { fatalError("Failed to create container") } }() This builds fine, however, when I run it in previews, it crashes about 50% of the time with the following error: CoreData: error: SQLCore dispatchRequest: exception handling request: <NSSQLSaveChangesRequestContext: 0x60000370ca80> , -[__NSDictionaryM UTF8String]: unrecognized selector sent to instance 0x60000024c760 with userInfo of (null) *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSDictionaryM UTF8String]: unrecognized selector sent to instance 0x60000024c760' When researching the problem, I only found this GitHub issue from 2018, which was never resolved (it was closed due to inactivity). The issue comments suggest that it is a Core Data issue caused by a "dangling pointer" and "memory and race conditions". This is the definition of the Book model. Most of the values are optional because the data will be entered automatically from sources that may have incomplete data. @Model final class Book { var name: String? var author: String? var year: Int? var isbn: ISBN? var shelf: Shelf? var collections: [Collection] var marcXML: Data? let dateCaptured: Date() init(name: String? = nil, author: String? = nil, year: Int? = nil, isbn: ISBN? = nil, shelf: Shelf? = nil, marcXML: Data? = nil, collections: [Collection]? = nil) { self.name = name self.author = author self.year = year self.isbn = isbn self.shelf = shelf self.dateCaptured = Date() self.marcXML = marcXML self.collections = collections ?? [] } }
0
0
217
Mar ’24
SwiftData not syncing with iCloud
Hello everyone, I followed this (https://www.hackingwithswift.com/quick-start/swiftdata/how-to-sync-swiftdata-with-icloud) guide from Paul Hudson on how to sync swiftdata with iCloud. I tried it on my device directly and it worked exactly as I would expect. Now I tried the same version of the app on another device installed through TestFlight external tester group. It no longer works. When deleting the app, the alert reads "Deleting this app will also delete its data, but any documents or data will be stored in iCloud will not be deleted" so the app should have said something in iCloud. When looking in Settings -> Your Name -> iCloud -> Manage Account Storage, on the working device I can see around 300 KB saved in iCloud, on the other device my app is not listed. Both have a fast and working internet connection, almost fully charged, low data mode turned off, running 17.4.1, Background modes enabled, Mobile data enabled, more than enough unused iCloud storage and plenty of time to sync. I was streaming the logs from the Cloudkit dashboard but nothing appeared there. The data saved neither syncs to another device of the same apple id nor reappears after app removal. The model Container is initialized without any configuration, the only relationship is optional and every value has a default value. There is A LOT of log noise when launching the app and I am unable to get any meaningful information from that. I can only get the log from the device where it is working as expected. I have triple checked that it is exactly the same app version and no debug conditions anywhere. I have absolutely no idea what is causing this. Thanks for any help :)
1
0
986
Mar ’24
LazyVStack with ScrollView's new features doesn't show content
Hi there, i'm currently trying to make a ChatView with SwiftUI. I've been using "inverted" ScrollView, but now I see new defaultScrollAnchor and scrollPosition methods which can make solution more kind of native and less buggy. So, here is the snippet of my implementation: ScrollView { LazyVStack { ForEach(messages) { message in MessageView( message: message, actions: viewModel.messageActions ) } } } .defaultScrollAnchor(.bottom) At this point it works as expected most of the time. But once I have a message which content doesn't fit on the screen there is the problem. When I enter the chat for the first time all is OK: But next times I open the chat i see only this: But the content is scrollable, once i scroll a little bit to the top, messages appear like they just were scrolled. I think this is the problem with LazyVStack, maybe it waits for the content top to be displayed to render item? Here is the full code of my ChatView: import Foundation import SwiftUI import SwiftData import AlertKit import Factory struct ChatView: View { @StateObject private var viewModel: ChatViewModel @Environment(\.modelContext) private var modelContext @Query private var messages: [ChatMessage] @Query private var generatingMessages: [ChatMessage] init(chat: Chat) { _viewModel = StateObject(wrappedValue: Container.shared.chatViewModel(chat)) let chatId = chat.persistentModelID _messages = Query( filter: #Predicate { $0.chat?.persistentModelID == chatId }, sort: \.date, animation: .spring ) _generatingMessages = Query( filter: #Predicate { $0.generating && $0.chat?.persistentModelID == chatId } ) } var body: some View { VStack(spacing: 0) { ScrollView { LazyVStack(spacing: 0) { ForEach(messages) { message in MessageView( message: message, actions: viewModel.messageActions ) } } } .defaultScrollAnchor(.bottom) if !messages.isEmpty { Divider() } HStack(alignment: .bottom) { TextField("message", text: $viewModel.text, axis: .vertical) .padding(.vertical, 7) .padding(.horizontal, 12) .background(Color(.secondarySystemBackground)) .clipShape(RoundedRectangle(cornerRadius: 20)) .onSubmit { sendMessage() } SendButton(enabled: generatingMessages.isEmpty) { sendMessage() } .animation(.default, value: generatingMessages.count) .padding(.vertical, 7) } .padding(.horizontal) .padding(.vertical, 10) } .toastingErrors(with: viewModel) .scrollDismissesKeyboard(.interactively) .navigationTitle(viewModel.chat.title ?? "") .navigationBarTitleDisplayMode(.inline) } private func sendMessage() { if viewModel.text.isEmpty { return } viewModel.startLoading() } } So, is there any workaround for this issue? Or maybe I do something wrong?
2
0
919
Mar ’24
Access an Object and Change Values. up to 2 Class Levels down
Hello together, I hope someone can answer and can give me maybe a little guidance. Is it possible to access and change a child value from a child class in SwiftData? I tried now different ways but couldn't get it to work although I don't get any errors but I am not able to change or set any values. So the code example below is only a simplified example and I know some minor errors but it is about the principle. Can the Father class access somehow the Children class and for example read the childrenName? @Model class Father { var father: String var child: Child? } @Model class Child { var childName: String var child: Children? var father: Father } @Model class Children { var childrenName: String var parent: Child } I don't need direct access from the Father to the Children class - it has to go via the child class. Thanks for any direction or feedback in advance.
3
0
267
Mar ’24