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

Post

Replies

Boosts

Views

Activity

Document-based SwiftData apps fail to identify a store on iPad?
When trying to run my document-based iPad app using iPadOS 18 beta and Xcode 16 beta, I get an error like the following after opening a document: Thread 1: Fatal error: Failed to identify a store that can hold instances of SwiftData._KKMDBackingData<MyProject.MyModel> from [:] In order to help track down what is going wrong, I downloaded the sample app from WWDC23 session "Build an app with SwiftData" found here: https://developer.apple.com/documentation/swiftui/building-a-document-based-app-using-swiftdata When I try to run the end-state of that sample code, I get a similar error when running the app on my iPad and creating a new deck: Thread 1: Fatal error: Failed to identify a store that can hold instances of SwiftData._KKMDBackingData<SwiftDataFlashCardSample.Card> from [:] Given that the sample project is generating the same error as my own project, is this a problem with SwiftData and document-based apps in general? Or is there a change of approach that I should try?
19
10
2.7k
Feb ’25
Proper way to use a ModelContext from a background thread in a document based app
What is the idiomatic way to use a ModelContext in a document based SwiftData app from a background thread? The relevant DocumentGroup initializers do not give us direct access to a ModelContainer, only to a ModelContext. Is it safe to take its modelContext.container and pass it around (for creating a ModelContext on it on a background thread) or to construct a ModelActor with it? Is it safe to e.g. put a ModelActor so created into the environment of the root view of the window and execute various async data operations on it in Tasks throughout the app, as long as these are dispatched from within the window whose root view's ModelContext was used for getting the ModelContainer?
1
1
684
Feb ’25
modelContext.fetch() hits assert on release builds, but not on debug builds
Exact same app works fine in debug builds, but on release builds I see this stacktrace indicating that assert() was hit. Incident Identifier: *** Distributor ID: com.apple.TestFlight Hardware Model: iPhone14,3 Process: AuditOS [67847] Path: /private/var/containers/Bundle/Application/*** Identifier: *** Version: 1.0 (15) AppStoreTools: 16C5031b AppVariant: 1:iPhone14,3:18 Beta: YES Code Type: ARM-64 (Native) Role: Foreground Parent Process: launchd [1] Coalition: *** Date/Time: 2025-02-11 12:37:54.7801 -0600 Launch Time: 2025-02-11 12:37:33.1737 -0600 OS Version: iPhone OS 18.3 (22D63) Release Type: User Baseband Version: 4.20.03 Report Version: 104 Exception Type: EXC_BREAKPOINT (SIGTRAP) Exception Codes: 0x0000000000000001, 0x000000019d388e2c Termination Reason: SIGNAL 5 Trace/BPT trap: 5 Terminating Process: exc handler [67847] Triggered by Thread: 0 Thread 0 Crashed: 0 libswiftCore.dylib 0x000000019d388e2c _assertionFailure(_:_:file:line:flags:) + 264 (AssertCommon.swift:147) 1 SwiftData 0x0000000261842e04 Schema.KeyPathCache.validateAndCache(keypath:on:) + 2628 (Schema.swift:0) 2 SwiftData 0x000000026178cac4 static PersistentModel.keyPathToString(keypath:) + 360 (DataUtilities.swift:36) 3 SwiftData 0x000000026184c9e4 static PersistentModel.fetchDescriptorKeyPathString(for:) + 36 (FetchDescriptor.swift:51) 4 SwiftData 0x00000002617b9770 closure #1 in PredicateExpressions.KeyPath.convert(state:) + 172 (FetchDescriptor.swift:458) 5 SwiftData 0x00000002617b7f48 PredicateExpressions.KeyPath.convert(state:) + 352 (FetchDescriptor.swift:438) 6 SwiftData 0x00000002617bb7ec protocol witness for ConvertibleExpression.convert(state:) in conformance PredicateExpressions.KeyPath&lt;A, B&gt; + 16 (&lt;compiler-generated&gt;:0) 7 SwiftData 0x00000002617baaa0 PredicateExpression.convertToExpressionOrPredicate(state:) + 716 (FetchDescriptor.swift:219) 8 SwiftData 0x00000002617ba6dc PredicateExpression.convertToExpression(state:) + 32 (FetchDescriptor.swift:237) 9 SwiftData 0x00000002617b7cfc PredicateExpressions.Equal.convert(state:) + 328 (:-1) 10 SwiftData 0x00000002617bba08 protocol witness for ConvertibleExpression.convert(state:) in conformance PredicateExpressions.Equal&lt;A, B&gt; + 64 (&lt;compiler-generated&gt;:0) 11 SwiftData 0x00000002617baaa0 PredicateExpression.convertToExpressionOrPredicate(state:) + 716 (FetchDescriptor.swift:219) 12 SwiftData 0x00000002617b7abc PredicateExpression.convertToPredicate(state:) + 28 (FetchDescriptor.swift:244) 13 SwiftData 0x00000002617b7190 nsFetchRequest&lt;A&gt;(for:in:) + 1204 (FetchDescriptor.swift:64) 14 SwiftData 0x0000000261783358 DefaultStore.fetch&lt;A&gt;(_:) + 292 (DefaultStore.swift:496) 15 SwiftData 0x000000026178322c protocol witness for DataStore.fetch&lt;A&gt;(_:) in conformance DefaultStore + 16 (&lt;compiler-generated&gt;:0) 16 SwiftData 0x00000002617847fc asDataStore #1 &lt;A&gt;&lt;A1&gt;(_:) in closure #1 in ModelContext.fetch&lt;A&gt;(_:) + 3152 (ModelContext.swift:2590) 17 SwiftData 0x00000002617a74d8 partial apply for closure #1 in ModelContext.fetch&lt;A&gt;(_:) + 100 (&lt;compiler-generated&gt;:0) 18 SwiftData 0x00000002617a7438 closure #1 in ModelContext.enumerateFetchableStores&lt;A&gt;(_:_:) + 208 (ModelContext.swift:2527) 19 SwiftData 0x00000002617a731c specialized ModelContext.enumerateFetchableStores&lt;A&gt;(_:_:) + 200 (ModelContext.swift:2522) 20 SwiftData 0x00000002617a6f08 ModelContext.fetch&lt;A&gt;(_:) + 144 (ModelContext.swift:2534) 21 SwiftData 0x00000002617a6e70 dispatch thunk of ModelContext.fetch&lt;A&gt;(_:) + 56 (:-1) 22 AuditOS 0x00000001041af3f4 0x10419c000 + 78836 23 AuditOS 0x00000001041bebd5 0x10419c000 + 142293 24 AuditOS 0x00000001041bbbf5 0x10419c000 + 130037 25 AuditOS 0x00000001041d8be5 0x10419c000 + 248805 26 AuditOS 0x00000001041bde6d 0x10419c000 + 138861 27 libswift_Concurrency.dylib 0x00000001aa6bfe39 completeTaskWithClosure(swift::AsyncContext*, swift::SwiftError*) + 1 (Task.cpp:497) The code in question looks like this: func addRecord&lt;T: MyDtoProtocol&gt;(_ someDTO: T) async throws { var zone: ZoneModel? = nil let recordName = someDTO.recordNameType let fetchDescriptor = FetchDescriptor&lt;T.ModelType&gt; (predicate: #Predicate {$0.recordName == recordName}) &gt; var localEntitites: [T.ModelType] = try modelContext.fetch(fetchDescriptor) &lt;---- I have isolated crash to this line. Basically for each swiftdata model type I have associatedType for Data Transfer Object type and vice versa.
4
1
867
Feb ’25
Signal SIGABRT on accessing values from SwiftData query
I work on an iOS app using SwiftUI and SwiftData. I added a computed property to one of my models - Parent - that uses relationship - array of Child models - data and I started getting strange problems. Let me start with models: @Model final class Parent { var name: String @Relationship(deleteRule: .cascade, inverse: \Child.parent) var children: [Child]? = [] var streak: Int { // Yes, I know that's not optimal solution for such counter ;) guard let children = children?.sorted(using: SortDescriptor(\.date, order: .reverse)) else { return 0 } var date = Date.now let calendar = Calendar.current for (index, child) in children.enumerated() { if !calendar.isDate(child.date, inSameDayAs: date) { return index } date = calendar.date(byAdding: .day, value: -1, to: date) ?? .now } return children.count } init(name: String) { self.name = name } } @Model final class Child { var date: Date @Relationship(deleteRule: .nullify) var parent: Parent? init(date: Date, parent: Parent) { self.date = date self.parent = parent } } At first everything works as expected. The problem arises once I try to remove one of child from the parent instance. I remove the value from context and save changes without any problems, at least not ones that can be caught by do { } catch. But instead of refreshing UI I get an signal SIGABRT somewhere inside SwiftData internals that points to the line where I'm trying (inside View body) get a child from a Query: struct LastSevenDaysButtons: View { @Environment(\.modelContext) private var modelContext @Query private var children: [Child] private let dates: [Date] private let parent: Parent init(for parent: Parent) { self.parent = parent var lastSevenDays = [Date]() let calendar = Calendar.current let firstDate = calendar.date(byAdding: .day, value: -6, to: calendar.startOfDay(for: .now)) ?? .now var date = firstDate while date <= .now { lastSevenDays.append(date) date = calendar.date(byAdding: .day, value: 1, to: date) ?? .now } dates = lastSevenDays let parentId = parent.persistentModelID _children = Query( filter: #Predicate { $0.parent?.persistentModelID == parentId && $0.date >= firstDate }, sort: [SortDescriptor(\Child.date, order: .reverse)], animation: .default ) } var body: some View { VStack { HStack(alignment: .top) { ForEach(dates, id: \.self) { date in // Here is the last point on stack from my code that I see let child = children.first { $0.date == date } Button { if let child { modelContext.delete(child) } else { modelContext.insert(Child(date: date, parent: parent)) } do { try modelContext.save() } catch { print("Can't save changes for \(parent.name) on \(date.formatted(date: .abbreviated, time: .omitted)): \(error.localizedDescription)") } } label: { Text("\(date.formatted(date: .abbreviated, time: .omitted))") .foregroundStyle(child == nil ? .red : .blue) } } } } } } The LastSevenDaysButtons View is kind of deep in a View hierarchy: RootView -> ParentList -> ParentListItem -> LastSevenDaysButtons However once I move insides of ParentList to RootView application works just fine, although I see and warning: === AttributeGraph: cycle detected through attribute 6912 ===. What could be that I do wrong in here? I believe it must something I'm missing here, but after 2 days of debug, trial and errors, I can't think clearly anymore. Here is the minimal repro I managed to create: Signal SIGABRT on accessing values from SwiftData query
3
0
733
Feb ’25
SwiftData with shared and private containers
I was hoping for an update of SwiftData which adopted the use of shared and public CloudKit containers, in the same way it does for the private CloudKit container. So firstly, a big request to any Apple devs reading, for this to be a thing! Secondly, what would be a sensible way of adding a shared container in CloudKit to an existing app that is already using SwiftData? Would it be possible to use the new DataStore method to manage CloudKit syncing with a public or shared container?
11
18
3.6k
Feb ’25
SwiftData property marked ephemeral getting persisted in CloudKit
Am I misunderstanding the expected behavior here, or is there a bug in the behavior of @Attribute(.ephemeral) tagged SwiftData model properties? The documentation for .ephemeral says "Track changes to this property but do not persist". I started using .ephemeral because @Transient was inhibiting SwiftUI from reacting to changes to the property through @Observable. I am updating the value of my @Attribute(.ephemeral) property about once a second and I am seeing corresponding console log output showing the property as part of the generated CKRecord object. I then confirmed in the CloudKit dev portal that the .ephemeral property was added to the Record schema and contains real values. The behavior seems as though the .ephemeral property is being completely ignored. This is observed in a new Xcode project using SwiftData with CloudKit, Xcode 16.2, macOS 15.3.1 and during Build & Run testing on physical devices.
1
0
699
Feb ’25
Document based SwiftData apps do not autosave
Document based SwiftData apps do not autosave changes to the ModelContext at all. This issue has been around since the first release of this SwiftData feature. In fact, the Apple WWDC sample project (https://developer.apple.com/documentation/swiftui/building-a-document-based-app-using-swiftdata) does not persist any data in its current state, unless one inserts modelContext.save() calls after every data change. I have reported this under the feedback ID FB16503154, as it seemed to me that there is no feedback report about the fundamental issue yet. Other posts related to this problem: https://forums.developer.apple.com/forums/thread/757172 https://forums.developer.apple.com/forums/thread/768906 https://developer.apple.com/forums/thread/764189
0
0
303
Feb ’25
SwiftData One To Many
I'm working through the Develop In Swift tutorial at page [https://developer.apple.com/tutorials/develop-in-swift/navigation-editing-and-relationships-conclusion)] The tutorial has a one to many relationship between Friend and Movie (each friend can have at most one favorite movie and each movie can be the favorite for zero or more friends). An exercise left to the student is to use an .onDelete on the movie detail page to delete that movie as favorite. I modified the Form Form { TextField("Movie title", text: $movie.title) DatePicker("Release date", selection: $movie.releaseDate, displayedComponents: .date) if !movie.favoritedBy.isEmpty { Section("Favorited by") { ForEach(sortedFriends) { friend in Text(friend.name) } .onDelete(perform: deleteFavorites(indexes:)) } } } by adding the .onDelete clause I added private func deleteFavorites(indexes: IndexSet) { for index in indexes { context.delete(movie.favoritedBy[index]) } } to the view. This does delete the favorite movie, but it also deletes the friend. My assumption is that the selected friend should then have no favorite movie rather than being deleted There is an if in the Form that doesn't display the FAVORITED BY section if no friend has that movie as a favorite, but if I delete all the friends who had this movie as a favorite, the section remains (but is empty), until I exit the MovieDetail view and reload it There is no answer for these exercises, so I could be doing it wrong. EDIT: If I delete a movie using the app function to delete a movie, friends that have that movie as a favorite are not deleted and have their favorite movie set to None
3
0
763
Feb ’25
Unable to see data from a production environment
I am trying to test using Testflight and have set up a test with a user on an account I also own which is different to me developer account. The app I believe is running in production on a separate device and is working from a user point of view, however I am not able to query the data via the console. As I said I know the user id and password as tey are mine so even when I use the Act as user service it logs in but the query is empty. I'm assuming I'm not doing anything wrong its possibly an security issue that is preventing me accessing this account. My question to the group then is how do I verify the data that is being tested?
1
0
618
Feb ’25
SwiftData propertiesToFetch question
I have a simple model @Model final class Movie: Identifiable { #Index\<Movie\>(\[.name\]) var id = UUID() var name: String var genre: String? init(name: String, genre: String?) { self.name = name self.genre = genre } } I turned on SQL debugging by including '-com.apple.CoreData.SQLDebug 3' argument on launch. When I fetch the data using the following code, it selects 3 records initially, but then also selects each record individually even though I am not referencing any other attributes. var fetchDescriptor = FetchDescriptor\<Movie\>() fetchDescriptor.propertiesToFetch = \[.id, .name\] fetchDescriptor.fetchLimit = 3 do { print("SELECT START") movies = try modelContext.fetch(fetchDescriptor) print("SELECT END") } catch { print("Failed to load Movie model.") } I see it selecting the 3 rows initially, but then it selects each one separately. Why would it do this on the initial fetch? I was hoping to select the data that I want to display and let the system select the entire record only when I access a variable that I did not initially fetch. CoreData: annotation: fetch using NSSQLiteStatement <0x600002158af0> on entity 'Movie' with sql text 'SELECT 1, t0.Z_PK, t0.ZID, t0.ZNAME FROM ZMOVIE t0 LIMIT 3' returned 3 rows with values: ( "<NSManagedObject: 0x600002158d70> (entity: Movie; id: 0xa583c7ed484691c1 <x-coredata://71E60F4C-1A40-4DB7-8CD1-CD76B4C11949/Movie/p1>; data: <fault>)", "<NSManagedObject: 0x600002158d20> (entity: Movie; id: 0xa583c7ed482691c1 <x-coredata://71E60F4C-1A40-4DB7-8CD1-CD76B4C11949/Movie/p2>; data: <fault>)", "<NSManagedObject: 0x600002158f00> (entity: Movie; id: 0xa583c7ed480691c1 <x-coredata://71E60F4C-1A40-4DB7-8CD1-CD76B4C11949/Movie/p3>; data: <fault>)" ) CoreData: annotation: fetch using NSSQLiteStatement <0x600002154d70> on entity 'Movie' with sql text 'SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZGENRE, t0.ZID, t0.ZNAME FROM ZMOVIE t0 WHERE t0.Z_PK = ? ' returned 1 rows CoreData: annotation: with values: ( "<NSSQLRow: 0x600000c89500>{Movie 1-1-1 genre=\"Horror\" id=4C5CB4EB-95D7-4DC8-B839-D4F2D2E96ED0 name=\"A000036\" and to-manys=0x0}" ) This all happens between the SELECT START and SELECT END print statements. Why is it fulfilling the faults immediately?
2
0
354
Feb ’25
Is it possible to track history using HistoryDescriptor in SwiftData?
Is it possible to track history using the new HistoryDescriptor feature in SwiftData? Or can I only get the current most recent data? Or is it possible to output the changed data itself, along with timestamps? I am hoping that it is possible to track by a standard feature like NSPersistentHistoryTransaction in CoreData. Do we still have to use a method in SwiftData that creates more tracking data itself?
4
0
1.2k
Feb ’25
SwiftData on iOS 18 extreme memory use
Hi, I've run into two problems using SwiftData in iOS 18 that are total show-stoppers for my app, causing it to run out of memory and be killed by the system. The same app runs fine on iOS 17. The two problems are inter-related in a way I can't exactly diagnose, but are easy to reproduce. Problem #1: Calling .count on the array that represents a relationship or Query causes the whole array of objects to be loaded into memory. Problem #2: When a @Model object is loaded, properties that are declared with .externalStorage are loaded unnecessarily, and use tons of memory. It's possible that #1 is normal behavior, exacerbated by #2. I've written a test app that demonstrates the extreme difference in memory usage between the OS Versions. It uses a typical navigation pattern, with content counts on the left-side view. Each item has one thumbnail and one large image in .externalStorge. GitHub Source When populated with 80 items, each containing one thumbnail and one large image in .externalStorge, the app launches in 17.5 using 29mb of memory. On iOS 18, in the same conditions, 592 mb. When the first folder is selected, causing a list of thumbnails to load, iOS 17 uses just 86mb. iOS 18 uses 599mb, implying that all image data has already been loaded. So I'm asking for help from Apple or the Community in finding a workaround. I've been advised that finding a workaround may be necessary, as this may not be addressed in 18.0. Thanks in advance for any insight. Radars: FB14323833, FB14323934 (See attached images, or try it yourself) (You may notice in the 18.0 screenshots that the item counts don't add up right. That's yet another 18.0-SwiftData anomaly regarding relationships that I haven't tackled yet, but is also demonstrated by the sample app.)
14
5
3.6k
Feb ’25
SwiftData integration for coexistence with CoreData Error: Persistent truncated
When integrating SwiftData for an already existing app that uses CoreData as data management, I encounter errors. When building the ModelContainer for the first time, the following error appears: Error: Persistent History (184) has to be truncated due to the following entities being removed (all Entities except for the 2 where I defined a SwiftData Model) class SwiftDataManager: ObservableObject { static let shared = SwiftDataManager() private let persistenceManager = PersistenceManager.shared private init(){} lazy var modelContainer: ModelContainer = { do { let storeUrl = persistenceManager.storeURL() let schema = Schema([ HistoryIncident.self, HistoryEvent.self ]) let modelConfig = ModelConfiguration(url: storeUrl) return try ModelContainer(for: schema, configurations: [modelConfig]) } catch { fatalError("Could not create ModelContainer: \(error)") } }() } @Model public class HistoryIncident { var missionNr: String? @Relationship(deleteRule: .cascade) var events: [HistoryEvent]? public init(){} } @Model class HistoryEvent { var decs: String? var timestamp: Date? init(){} } As soon as I call the following function. func addMockEventsToCurrentHistorie() { var descriptor = FetchDescriptor<HistoryIncident>() let key = self.hKey ?? "" descriptor.predicate = #Predicate { mE in key == mE.key } let historyIncident = try? SwiftDataManager.shared.modelContext.fetch(descriptor).first guard var events = historyIncident?.events else {return} events.append(contentsOf: createEvents()) } I get the error: CoreData: error: (1) I/O error for database at /var/mobile/Containers/Data/Application/55E9D59D-48C4-4D86-8D9F-8F9CA019042D/Library/ Private Documents/appDatabase.sqlite. SQLite error code:1, 'no such column: t0.Z1EVENTS' /var/mobile/Containers/Data/Application/55E9D59D-48C4-4D86-8D9F-8F9CA019042D/Library/ Private Documents/appDatabase.sqlite. SQLite error code:1, 'no such column: t0.Z1EVENTS' with userInfo of { NSFilePath = "/var/mobile/Containers/Data/Application/55E9D59D-48C4-4D86-8D9F-8F9CA019042D/Library/ Private Documents/appDatabase.sqlite"; NSSQLiteErrorDomain = 1; }
1
0
639
Feb ’25
iOS 18.3: "Fatal error: Failed to validate ..." when calling fetchHistory for HistoryTransaction
I'm converting SwiftData models into structs so I can fetch them in the background. To know when and which ones I need to update, I'm using iOS 18's new HistoryTransaction. Starting with iOS 18.3 (worked perfectly fine before), I'm getting this crash every time: Thread 18: Fatal error: Failed to validate placeVideosIn.placeVideosIn because placeVideosIn is not a member of VideoPlacement The crash is happening here: static func findTransactions(after token: DefaultHistoryToken?) -> [DefaultHistoryTransaction] { var historyDescriptor = HistoryDescriptor<DefaultHistoryTransaction>() if let token { historyDescriptor.predicate = #Predicate { transaction in (transaction.token > token) } } var transactions: [DefaultHistoryTransaction] = [] let taskContext = ModelContext(container) do { transactions = try taskContext.fetchHistory(historyDescriptor) // <- CRASH } catch let error { Logger.log.warning("findTransactions Error: \(error)") } return transactions } The SwiftData model has this enum property: @Model public final class Subscription { // ... public var placeVideosIn = VideoPlacement.defaultPlacement } The enum looks like this: public enum VideoPlacement: Int { case inbox = 0 case queueNext = 1 case nothing = 2 case defaultPlacement = 3 case queueLast = 4 } The enum has changed at one point, but I was expecting that change to be transparent/additive. It looked like this before: public enum VideoPlacement: Int { case inbox, queue, nothing, defaultPlacement } Changing all values manually to e.g. .defaultPlacement did not fix the crash. What did fix it was deleting all HistoryTransactions: var descriptor = HistoryDescriptor<DefaultHistoryTransaction>() try modelContext.deleteHistory(descriptor) For some reason, deleting all HistoryTransactions sometimes also deletes actual models. Is that to be expected? Any idea how I could attempt to fix this issue?
2
2
1k
Jan ’25
SwiftUI and UIImage memory leak
I’m experiencing significant performance and memory management issues in my SwiftUI application when displaying a large number of images using LazyVStack within a ScrollView. The application uses Swift Data to manage and display images. Here’s the model I’m working with: @Model final class Item { var id: UUID = UUID() var timestamp: Date = Date.now var photo: Data = Data() init(photo: Data = Data(), timestamp: Date = Date.now) { self.photo = photo self.timestamp = timestamp } } extension Item: Identifiable {} The photo property is used to store images. However, when querying Item objects using Swift Data in a SwiftUI ScrollView, the app crashes if there are more than 100 images in the database. Scrolling down through the LazyVStack loads all images into memory leading to the app crashing when memory usage exceeds the device’s limits. Here’s my view: A LazyVStack inside a ScrollView displays the images. struct LazyScrollView: View { @Environment(\.modelContext) private var modelContext @State private var isShowingPhotosPicker: Bool = false @State private var selectedItems: [PhotosPickerItem] = [] @Query private var items: [Item] var body: some View { NavigationStack { ScrollView { LazyVStack { ForEach(items) { item in NavigationLink { Image(uiImage: UIImage(data: item.photo)!) .resizable() .scaledToFit() } label: { Image(uiImage: UIImage(data: item.photo)!) .resizable() .scaledToFit() } } } } .navigationTitle("LazyScrollView") .photosPicker(isPresented: $isShowingPhotosPicker, selection: $selectedItems, maxSelectionCount: 100, matching: .images) .onChange(of: selectedItems) { Task { for item in selectedItems { if let data = try await item.loadTransferable(type: Data.self) { let newItem = Item(photo: data) modelContext.insert(newItem) } } try? modelContext.save() selectedItems = [] } } } } } Based on this: How can I prevent SwiftUI from loading all the binary data (photo) into memory when the whole view is scrolled until the last item? Why does SwiftUI not free memory from the images that are not being displayed? Any insights or suggestions would be greatly appreciated. Thank you! I will put the full view code in the comments so anyone can test if needed.
2
0
690
Jan ’25
No insert animation after `insert` when using SwiftData.
Hi, After running the Xcode template "New project > (SwiftUI, SwiftData)" I noticed that there is no insert animation into the list. The project is a pure vanilla project created from Xcode (Version 16.2 (16C5032a)) and the code is a simple as it gets: // // ContentView.swift // import SwiftUI import SwiftData struct ContentView: View { @Environment(\.modelContext) private var modelContext @Query private var items: [Item] var body: some View { NavigationSplitView { List { ForEach(items) { item in NavigationLink { Text("Item at \(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))") } label: { Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard)) } } .onDelete(perform: deleteItems) } .toolbar { ToolbarItem(placement: .navigationBarTrailing) { EditButton() } ToolbarItem { Button(action: addItem) { Label("Add Item", systemImage: "plus") } } } } detail: { Text("Select an item") } } private func addItem() { withAnimation { let newItem = Item(timestamp: Date()) modelContext.insert(newItem) } } private func deleteItems(offsets: IndexSet) { withAnimation { for index in offsets { modelContext.delete(items[index]) } } } } #Preview { ContentView() .modelContainer(for: Item.self, inMemory: true) } As you see the template's code does have withAnimation inside addItem but there is no animation. The new added item appears without animation in the the List Here is a short video. Is this a known bug?
4
0
866
Jan ’25
Data Protection and SwiftData Containers
SwiftData ModelContainer instances don't seem to have a value for setting the Data Protection class. Is the best way to set that by setting the Data Protection in the app capabilities? Is that the only way? I have a need for log data that would be "Complete unless open" and user data that would be "Complete", but how do I change one of the containers data protection class?
2
1
867
Jan ’25
Fatal error: Duplicate keys of type 'AnyHashable' were found in a Dictionary
I get the following fatal error when the user clicks Save in AddProductionView. Fatal error: Duplicate keys of type 'AnyHashable' were found in a Dictionary. This usually means either that the type violates Hashable's requirements, or that members of such a dictionary were mutated after insertion. As far as I’m aware, SwiftData automatically makes its models conform to Hashable, so this shouldn’t be a problem. I think it has something to do with the picker, but for the life of me I can’t see what. This error occurs about 75% of the time when Save is clicked. I'm using Xcode 16.2 and iPhone SE 2nd Gen. Any help would be greatly appreciated… Here is my code: import SwiftUI import SwiftData @main struct MyApp: App { var body: some Scene { WindowGroup { ContentView() .modelContainer(for: Character.self, isAutosaveEnabled: false) } } } @Model final class Character { var name: String var production: Production var myCharacter: Bool init(name: String, production: Production, myCharacter: Bool = false) { self.name = name self.production = production self.myCharacter = myCharacter } } @Model final class Production { var name: String init(name: String) { self.name = name } } struct ContentView: View { @State private var showingSheet = false var body: some View { Button("Add", systemImage: "plus") { showingSheet.toggle() } .sheet(isPresented: $showingSheet) { AddProductionView() } } } struct AddProductionView: View { @Environment(\.dismiss) private var dismiss @Environment(\.modelContext) var modelContext @State var production = Production(name: "") @Query var characters: [Character] @State private var characterName: String = "" @State private var selectedCharacter: Character? var filteredCharacters: [Character] { characters.filter { $0.production == production } } var body: some View { NavigationStack { Form { Section("Details") { TextField("Title", text: $production.name) } Section("Characters") { List(filteredCharacters) { character in Text(character.name) } HStack { TextField("Character", text: $characterName) Button("Add") { let newCharacter = Character(name: characterName, production: production) modelContext.insert(newCharacter) characterName = "" } .disabled(characterName.isEmpty) } if !filteredCharacters.isEmpty { Picker("Select your role", selection: $selectedCharacter) { Text("Select") .tag(nil as Character?) ForEach(filteredCharacters) { character in Text(character.name) .tag(character as Character?) } } .pickerStyle(.menu) } } } .toolbar { Button("Save") { //Fatal error: Duplicate keys of type 'AnyHashable' were found in a Dictionary. This usually means either that the type violates Hashable's requirements, or that members of such a dictionary were mutated after insertion. if let selectedCharacter = selectedCharacter { selectedCharacter.myCharacter = true } modelContext.insert(production) do { try modelContext.save() } catch { print("Failed to save context: \(error)") } dismiss() } .disabled(production.name.isEmpty || selectedCharacter == nil) } } } }
2
0
843
Jan ’25
Not able to save with SwiftData. "The file “default.store” couldn’t be opened."
I get this message when trying to save my Models. CoreData: error: SQLCore dispatchRequest: exception handling request: <NSSQLSaveChangesRequestContext: 0x303034540> , I/O error for database at /var/mobile/Containers/Data/Application/726ECA8C-6C67-4BFE-89E7-AFD8A83CAA5D/Library/Application Support/default.store. SQLite error code:1, 'no such table: ZCALENDARMODEL' with userInfo of { NSFilePath = "/var/mobile/Containers/Data/Application/726ECA8C-6C67-4BFE-89E7-AFD8A83CAA5D/Library/Application Support/default.store"; NSSQLiteErrorDomain = 1; } SwiftData.DefaultStore save failed with error: Error Domain=NSCocoaErrorDomain Code=256 "The file “default.store” couldn’t be opened." UserInfo={NSFilePath=/var/mobile/Containers/Data/Application/726ECA8C-6C67-4BFE-89E7-AFD8A83CAA5D/Library/Application Support/default.store, NSSQLiteErrorDomain=1} The App has Recipes and Calendars and the user can select a Recipe for each Calendar day. The recipe should not be referenced, it should be saved by SwiftData along with the Calendar. import SwiftUI import SwiftData enum CalendarSource: String, Codable { case created case imported } @Model class CalendarModel: Identifiable, Codable { var id: UUID = UUID() var name: String var startDate: Date var endDate: Date var recipes: [String: RecipeData] = [:] var thumbnailData: Data? var source: CalendarSource? // Computed Properties var daysBetween: Int { let days = Calendar.current.dateComponents([.day], from: startDate.midnight, to: endDate.midnight).day ?? 0 return days + 1 } var allDates: [Date] { startDate.midnight.allDates(upTo: endDate.midnight) } var thumbnailImage: Image? { if let data = thumbnailData, let uiImage = UIImage(data: data) { return Image(uiImage: uiImage) } else { return nil } } // Initializer init(name: String, startDate: Date, endDate: Date, thumbnailData: Data? = nil, source: CalendarSource? = .created) { self.name = name self.startDate = startDate self.endDate = endDate self.thumbnailData = thumbnailData self.source = source } // Convenience initializer to create a copy of an existing calendar static func copy(from calendar: CalendarModel) -> CalendarModel { let copiedCalendar = CalendarModel( name: calendar.name, startDate: calendar.startDate, endDate: calendar.endDate, thumbnailData: calendar.thumbnailData, source: calendar.source ) // Copy recipes copiedCalendar.recipes = calendar.recipes.mapValues { $0 } return copiedCalendar } // Codable Conformance private enum CodingKeys: String, CodingKey { case id, name, startDate, endDate, recipes, thumbnailData, source } required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) id = try container.decode(UUID.self, forKey: .id) name = try container.decode(String.self, forKey: .name) startDate = try container.decode(Date.self, forKey: .startDate) endDate = try container.decode(Date.self, forKey: .endDate) recipes = try container.decode([String: RecipeData].self, forKey: .recipes) thumbnailData = try container.decodeIfPresent(Data.self, forKey: .thumbnailData) source = try container.decodeIfPresent(CalendarSource.self, forKey: .source) } func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(id, forKey: .id) try container.encode(name, forKey: .name) try container.encode(startDate, forKey: .startDate) try container.encode(endDate, forKey: .endDate) try container.encode(recipes, forKey: .recipes) try container.encode(thumbnailData, forKey: .thumbnailData) try container.encode(source, forKey: .source) } } import SwiftUI struct RecipeData: Codable, Identifiable { var id: UUID = UUID() var name: String var ingredients: String var steps: String var thumbnailData: Data? // Computed property to convert thumbnail data to a SwiftUI Image var thumbnailImage: Image? { if let data = thumbnailData, let uiImage = UIImage(data: data) { return Image(uiImage: uiImage) } else { return nil // No image } } init(recipe: RecipeModel) { self.name = recipe.name self.ingredients = recipe.ingredients self.steps = recipe.steps self.thumbnailData = recipe.thumbnailData } } import SwiftUI import SwiftData @Model class RecipeModel: Identifiable, Codable { var id: UUID = UUID() var name: String var ingredients: String var steps: String var thumbnailData: Data? // Store the image data for the thumbnail static let fallbackSymbols = ["book.pages.fill", "carrot.fill", "fork.knife", "stove.fill"] // Computed property to convert thumbnail data to a SwiftUI Image var thumbnailImage: Image? { if let data = thumbnailData, let uiImage = UIImage(data: data) { return Image(uiImage: uiImage) } else { return nil // No image } } // MARK: - Initializer init(name: String, ingredients: String = "", steps: String = "", thumbnailData: Data? = nil) { self.name = name self.ingredients = ingredients self.steps = steps self.thumbnailData = thumbnailData } // MARK: - Copy Function func copy() -> RecipeModel { RecipeModel( name: self.name, ingredients: self.ingredients, steps: self.steps, thumbnailData: self.thumbnailData ) } // MARK: - Codable Conformance private enum CodingKeys: String, CodingKey { case id, name, ingredients, steps, thumbnailData } required init(from decoder: Decoder) throws { ... } func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(id, forKey: .id) try container.encode(name, forKey: .name) try container.encode(ingredients, forKey: .ingredients) try container.encode(steps, forKey: .steps) try container.encode(thumbnailData, forKey: .thumbnailData) } }
1
0
908
Jan ’25
SwiftData Relationship Delete Not Working (SwiftData/PersistentModel.swift:359)
SwiftData delete isn't working, when I attempt to delete a model, my app crashes and I get the following error: SwiftData/PersistentModel.swift:359: Fatal error: Cannot remove My_App.Model2 from relationship Relationship - name: model2, options: [], valueType: Model2, destination: Model2, inverseName: models3, inverseKeypath: Optional(\Model2.models3) on My_App.Model3 because an appropriate default value is not configured. I get that it's saying I don't have a default value, but why do I need one? Isn't @Relationship .cascade automatically deleting the associated models? And onto of that, why is the error occurring within the do block, shouldn't it be caught by the catch, and printed? I have put together a sample project below. import SwiftUI import SwiftData @main struct MyApp: App { var body: some Scene { WindowGroup { ContentView() .modelContainer(for: Model3.self) } } } @Model class Model1 { var name: String @Relationship(deleteRule: .cascade, inverse: \Model2.model1) var models2: [Model2] = [] init(name: String) { self.name = name } } @Model class Model2 { var name: String var model1: Model1 @Relationship(deleteRule: .cascade, inverse: \Model3.model2) var models3: [Model3] = [] init(name: String, model1: Model1) { self.name = name self.model1 = model1 } } @Model class Model3 { var name: String var model2: Model2 init(name: String, model2: Model2) { self.name = name self.model2 = model2 } } struct ContentView: View { @Query var models1: [Model1] @Environment(\.modelContext) var modelContext var body: some View { NavigationStack { List(models1) { model1 in Text(model1.name) .swipeActions { Button("Delete", systemImage: "trash", role: .destructive) { modelContext.delete(model1) do { try modelContext.save() //SwiftData/PersistentModel.swift:359: Fatal error: Cannot remove My_App.Model2 from relationship Relationship - name: model2, options: [], valueType: Model2, destination: Model2, inverseName: models3, inverseKeypath: Optional(\Model2.models3) on My_App.Model3 because an appropriate default value is not configured. } catch { print(error.localizedDescription) } } } } .toolbar { Button("Insert", systemImage: "plus") { modelContext.insert(Model3(name: "model3", model2: Model2(name: "model2", model1: Model1(name: "model1")))) } } } } }
1
0
1.1k
Jan ’25