Issue with SwiftData: “no such table: ZAPPSETTINGS” and SQLite I/O error on app launch
Hello,
I’m encountering persistent errors with SwiftData in my SwiftUI app related to Core Data’s underlying SQLite database. Despite defining my models correctly, the app fails to initialize the persistent store, throwing the following error on startup:
CoreData error: SQLCore dispatchRequest: no such table: ZAPPSETTINGS. I/O error opening database at /.../default.store. SQLite error code:1, NSSQLiteErrorDomain=1.
File “default.store” couldn’t be opened.
Context
The error only appears concerning my AppSettings model.
I have another model, LocationPoint, which appears correctly defined and used.
I have tried deleting the app, resetting the device, and cleaning builds but the error persists.
The error message suggests the database file is present but the table for ZAPPSETTINGS (the Core Data table for AppSettings) does not exist.
Code Samples
Main App Entry
import SwiftData
import SwiftUI
@main
struct Krow3_0App: App {
@State private var userLocationManager = UserLocationManager()
@State private var geocodingViewModel = GeocodingViewModel()
@State private var locationSearchViewModel = LocationSearchViewModel()
@State private var router = Router()
var body: some Scene {
WindowGroup {
LaunchView()
.environment(userLocationManager)
.environment(geocodingViewModel)
.environment(locationSearchViewModel)
.environment(router)
.modelContainer(for: [LocationPoint.self, AppSettings.self])
}
}
}
AppSettings Model
import Foundation
import SwiftData
@Model
class AppSettings {
var isMetric: Bool
init(isMetric: Bool = false) {
self.isMetric = isMetric
}
}
What I’ve Tried
Fully uninstalling and reinstalling the app on device and simulator.
Resetting the simulator/device.
Cleaning the Xcode build folder.
Verifying the schema logs which correctly list both LocationPoint and AppSettings.
Changing model names to avoid potential conflicts.
Adding .modelContainer configuration with autosave enabled.
Questions
Is there a known bug or limitation with SwiftData concerning certain model setups or naming?
Could this be related to how the data container initializes or migrates schemas?
Are there recommended debugging or migration steps to resolve “no such table” SQLite errors with SwiftData?
How can I safely reset or migrate the persistent store without corrupting the database?
Any insights or suggestions would be greatly appreciated!
Thank you!
SwiftData
RSS for tagSwiftData 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
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I have an issue in my app, where the crashing frame is an assertionFailure in BackingData.set inside SwiftData framework. My own app doesn't appear until frame 14. I have no idea what causes this, or even how to create a reproducible project as this only happens on some devices.
The frame prior to the assertionFailure is this:
#1 (null) in BackingData.set(any:value:) ()
It seems like there is a backing data encoding happening in my Model class, and some value is causing it to fail. The model being accessed is through a relationship, and the frame in the app crashing is along the lines of
Text(parent.child.name)
Obviously, something is wrong in how I have made child, but the part that stand out to me is the assertionFailure in a release build
I'm writing some tests to confirm the behavior of my app. White creating a model actor to delete objects I realized that ModelContext.model(for:) does return objects that are deleted. I was able to reproduces this with this minimal test case:
@Model class Activity {
init() {}
}
struct MyLibraryTests {
let modelContainer = try! ModelContainer(
for: Activity.self,
configurations: ModelConfiguration(
isStoredInMemoryOnly: true
)
)
init() throws {
let context = ModelContext(modelContainer)
context.insert(Activity())
try context.save()
}
@Test func modelForIdAfterDelete() async throws {
let context = ModelContext(modelContainer)
let id = try context.fetch(FetchDescriptor<Activity>()).first!.id
context.delete(context.model(for: id) as! Activity)
try context.save()
let result = context.model(for: id) as? Activity
#expect(result == nil) // Expectation failed: (result → MyLibrary.Activity) == nil
}
@Test func fetchDescriptorAfterDelete() async throws {
let context = ModelContext(modelContainer)
let id = try context.fetch(FetchDescriptor<Activity>()).first!.id
context.delete(context.model(for: id) as! Activity)
try context.save()
let result = try context.fetch(
FetchDescriptor<Activity>(predicate: #Predicate { $0.id == id })
).first
#expect(result == nil)
}
}
Here I create a new context, insert an model and save it.
The test modelForIdAfterDelete does fail, as result still contains the deleted object.
I also tried to check #expect(result!.isDeleted), but it is also false.
With the second test I use a FetchDescriptor to retrieve the object by ID and it correctly returns nil.
Shouldn't both methods use a consistent behavior?
Problem
The following code doesn't work:
let predicate = #Predicate<Car> { car in
car.size == size //This doesn't work
}
Console Error
Query encountered an error: SwiftData.SwiftDataError(_error: SwiftData.SwiftDataError._Error.unsupportedPredicate)
Root cause
Size is an enum, #Predicate works with other type such as String however doesn't work with enum
Enum value is saved however is not filtered by #Predicate
Environment
Xcode: 15.0 (15A240d) - App Store
macOS: 14.0 (23A339) - Release Candidate
Steps to reproduce
Run the app on iOS 17 or macOS Sonoma
Press the Add button
Notice that the list remains empty
Expected behaviour
List should show the newly created small car
Actual behaviour
List remains empty inspite of successfully creating the small car.
Feedback
FB13194334
Code
Size
enum Size: String, Codable {
case small
case medium
case large
}
Car
import SwiftData
@Model
class Car {
let id: UUID
let name: String
let size: Size
init(
id: UUID,
name: String,
size: Size
) {
self.id = id
self.name = name
self.size = size
}
}
ContentView
struct ContentView: View {
var body: some View {
NavigationStack {
CarList(size: .small)
}
}
CarList
import SwiftUI
import SwiftData
struct CarList: View {
let size: Size
@Environment(\.modelContext)
private var modelContext
@Query
private var cars: [Car]
init(size: Size) {
self.size = size
let predicate = #Predicate<Car> { car in
car.size == size //This doesn't work
}
_cars = Query(filter: predicate, sort: \.name)
}
var body: some View {
List(cars) { car in
VStack(alignment: .leading) {
Text(car.name)
Text("\(car.size.rawValue)")
Text(car.id.uuidString)
.font(.footnote)
}
}
.toolbar {
Button("Add") {
createCar()
}
}
}
private func createCar() {
let name = "aaa"
let car = Car(
id: UUID(),
name: name,
size: size
)
modelContext.insert(car)
}
}
Hi !
Would anyone know (if possible) how to create backup files to export and then import from the data recorded by SwiftData?
For those who wish, here is a more detailed explanation of my case:
I am developing a small management software with customers and events represented by distinct classes. I would like to have an "Export" button to create a file with all the instances of these 2 classes and another "Import" button to replace all the old data with the new ones from a previously exported file.
I looked for several solutions but I'm a little lost...
I'm using SwiftData with CloutKit with a very simple app. Data syncs between iOS, iPadOS, and visionOS, but not macOS. From what I can tell, macOS is never getting CK messages unless I'm running the app from Xcode.
I can listen for the CK messages and show a line in a debug overlay. This works perfectly when I run from Xcode. I can see the notifications and see updates in my app. However, if I just launch the app outside of Xcode I will never see any changes or notifications. It is as if the Mac app never even tries to contact CloudKit.
Schema has been deployed in the CloudKit console. The app is based on the multi-platform Xcode template. Again, only the macOS version has this issue. Is there some extra permission or setting I need to set up in order to use CloudKit on macOS?
@State private var publisher = NotificationCenter.default.publisher(for: NSPersistentCloudKitContainer.eventChangedNotification).receive(on: DispatchQueue.main)
.onReceive(publisher) { notification in
// Listen for changes in CK events
if let userInfo = notification.userInfo,
let event = userInfo[NSPersistentCloudKitContainer.eventNotificationUserInfoKey] as? NSPersistentCloudKitContainer.Event {
let message = "CloudKit Sync: \(event.type.rawValue) - \(event.succeeded ? "Success" : "Failed") - \(event.description)"
// Store for UI display
syncNotifications.append(message)
if syncNotifications.count > 10 {
syncNotifications.removeFirst()
}
}
}
.overlay(alignment: .topTrailing) {
if !syncNotifications.isEmpty {
VStack(alignment: .leading) {
ForEach(syncNotifications, id: \.self) { notification in
Text(notification)
.padding(8)
}
}
.frame(width: 800, height: 500)
.cornerRadius(8)
.background(Color.secondary.opacity(0.2))
.padding()
.transition(.move(edge: .top))
}
}
I have a SwiftData document-based app. It is initialized like this:
@main
struct MyApp: App {
@State private var showTemplatePicker = false
@State private var documentCreationContinuation: CheckedContinuation<URL?, any Error>?
var body: some Scene {
DocumentGroup(editing: .myDocument, migrationPlan: MyMigrationPlan.self) {
CanvasView()
}
DocumentGroupLaunchScene(Text("My App")) {
NewDocumentButton("New", contentType: .canvasDocument) {
try await withCheckedThrowingContinuation { continuation in
documentCreationContinuation = continuation
showTemplatePicker = true
}
}
.fullScreenCover(isPresented: $showTemplatePicker) {
TemplateView(documentCreationContinuation: $documentCreationContinuation)
}
} background: {
Image("BoardVignette")
.resizable()
}
}
}
extension UTType {
static var canvasDocument: UTType {
UTType(importedAs: "com.example.MyApp.canvas")
}
}
Pressing the New button crashes with:
#0 0x00000001d3a6e12c in (1) suspend resume partial function for closure #1 () async -> () in SwiftUI.IdentifiedDocumentGroupDocumentCreation.createNewDocument(with: SwiftUI.IdentifiedDocumentGroupConfiguration, url: Swift.Optional<Foundation.URL>, newDocumentProvider: Swift.Optional<SwiftUI.AsyncNewDocumentProvider>, _: (Swift.Optional<SwiftUI.PlatformDocument>) -> ()) -> () ()
All sample code that I've seen uses a FileDocument but SwiftData's setup doesn't have one so it's not completely clear how you should be using NewDocumentButton with a SwiftData file.
The crash happens even before my prepareDocumentURL handler is called (I set a breakpoint and it never stops). My hunch is that the crash is because it's not able to match my contentType to a Document. Can anyone at Apple help? I don't think this use-case has been documented well.
SwiftData crashes 100% when fetching history of a model that contains an optional codable property that's updated:
SwiftData/Schema.swift:389: Fatal error: Failed to materialize a keypath for someCodableID.someID from CrashModel. It is possible that this path traverses a type that does not work with append(), please file a bug report with a test.
Would really appreciate some help or even a workaround.
Code:
import Foundation
import SwiftData
import Testing
struct VaultsSwiftDataKnownIssuesTests {
@Test
func testCodableCrashInHistoryFetch() async throws {
let container = try ModelContainer(
for: CrashModel.self,
configurations: .init(
isStoredInMemoryOnly: true
)
)
let context = ModelContext(container)
try SimpleHistoryChecker.hasLocalHistoryChanges(context: context)
// 1: insert a new value and save
let model = CrashModel()
model.someCodableID = SomeCodableID(someID: "testid1")
context.insert(model)
try context.save()
// 2: check history it's fine.
try SimpleHistoryChecker.hasLocalHistoryChanges(context: context)
// 3: update the inserted value before then save
model.someCodableID = SomeCodableID(someID: "testid2")
try context.save()
// The next check will always crash on fetchHistory with this error:
/*
SwiftData/Schema.swift:389: Fatal error: Failed to materialize a keypath for someCodableID.someID from CrashModel. It is possible that this path traverses a type that does not work with append(), please file a bug report with a test.
*/
try SimpleHistoryChecker.hasLocalHistoryChanges(context: context)
}
}
@Model final class CrashModel {
// optional codable crashes.
var someCodableID: SomeCodableID?
// these actually work:
//var someCodableID: SomeCodableID
//var someCodableID: [SomeCodableID]
init() {}
}
public struct SomeCodableID: Codable {
public let someID: String
}
final class SimpleHistoryChecker {
static func hasLocalHistoryChanges(context: ModelContext) throws {
let descriptor = HistoryDescriptor<DefaultHistoryTransaction>()
let history = try context.fetchHistory(descriptor)
guard let last = history.last else {
return
}
print(last)
}
}
I'm trying out putting most of my business logic in a Protocol that my @Model can conform to, but I'm running into a SwiftUI problem with a Binding that does not get magically offered up like it does when it the subview is not generic.
I have a pretty basic List with a ForEach that now can't properly pass to a generic view based on a protocol. When I try to make a binding manually in the row it says that "item is immutable"... but that also doesn't help me with the NavigationLink? Which is seeing the Binding not the ? But before when the subview was concrete to Thing, it took in the and made its own Binding once it hit the view. I'm unclear on precisely where the change happens and what I can do to work around it.
Before I go rearchitecting everything... is there a fix to get the NavigationLink to take on the object like before? What needs to be different?
I've tried a number of crazy inits on the subview and they all seem to come back to saying either it can't figure out how to pass the type or I'm trying to use the value before it's been initialized.
Have I characterized the problem correctly?
Thanks!
(let me know if I forgot a piece of code, but this should be the List, the Model/Protocol and the subview)
import SwiftUI
import SwiftData
struct ThingsView: View {
@Environment(\.modelContext) var modelContext
@Query var items: [Thing]
var body: some View {
NavigationStack {
List {
ForEach(items) { item in
NavigationLink(value: item) {
VStack(alignment: .leading) {
Text(item.textInfo)
.font(.headline)
Text(item.timestamp.formatted(date: .long, time: .shortened))
}
}
}.onDelete(perform: deleteItems)
}
.navigationTitle("Fliiiing!")
//PROBLEM HERE: Cannot convert value of type '(Binding<Thing>) -> EditThingableView<Thing>' to expected argument type '(Thing) -> EditThingableView<Thing>'
.navigationDestination(for: Thing.self, destination: EditThingableView<Thing>.init)
#if os(macOS)
.navigationSplitViewColumnWidth(min: 180, ideal: 200)
#endif
.toolbar {
#if os(iOS)
ToolbarItem(placement: .navigationBarTrailing) {
EditButton()
}
#endif
ToolbarItem {
Button(action: addItem) {
Label("Add Item", systemImage: "plus")
}
}
ToolbarItem {
Button("Add Samples", action: addSamples)
}
}
}
}
func addSamples() {
withAnimation {
ItemSDMC.addSamples(context: modelContext)
}
}
private func addItem() {
withAnimation {
let newItem = ItemSDMC("I did a thing!")
modelContext.insert(newItem)
}
}
func deleteItems(_ indexSet:IndexSet) {
withAnimation {
for index in indexSet {
items[index].delete(from: modelContext)
}
}
}
}
#Preview {
ThingsView().modelContainer(for: ItemSDMC.self, inMemory: true)
}
import Foundation
import SwiftData
protocol Thingable:Identifiable {
var textInfo:String { get set }
var timestamp:Date { get set }
}
extension Thingable {
var thingDisplay:String {
"\(textInfo) with \(id) at \(timestamp.formatted(date: .long, time: .shortened))"
}
}
extension Thingable where Self:PersistentModel {
var thingDisplayWithID:String {
"\(textInfo) with modelID \(self.persistentModelID.id) in \(String(describing: self.persistentModelID.storeIdentifier)) at \(timestamp.formatted(date: .long, time: .shortened))"
}
}
struct ThingLite:Thingable, Codable, Sendable {
var textInfo: String
var timestamp: Date
var id: Int
}
@Model
final class Thing:Thingable {
//using this default value requires writng some clean up logic looking for empty text info.
var textInfo:String = ""
//using this default value would require writing some data clean up functions looking for out of bound dates.
var timestamp:Date = Date.distantPast
init(textInfo: String, timestamp: Date) {
self.textInfo = textInfo
self.timestamp = timestamp
}
}
extension Thing {
var LiteThing:ThingLite {
ThingLite(textInfo: textInfo, timestamp: timestamp, id: persistentModelID.hashValue)
}
}
import SwiftUI
struct EditThingableView<DisplayItemType:Thingable>: View {
@Binding var thingHolder: DisplayItemType
var body: some View {
VStack {
Text(thingHolder.thingDisplay)
Form {
TextField("text", text:$thingHolder.textInfo)
DatePicker("Date", selection: $thingHolder.timestamp)
}
}
#if os(iOS)
.navigationTitle("Edit Item")
.navigationBarTitleDisplayMode(.inline)
#endif
}
}
//NOTE: First sign of trouble
//#Preview {
// @Previewable var myItem = Thing(textInfo: "Example Item for Preview", timestamp:Date())
// EditThingableView<Thing>(thingHolder: myItem)
//}
I'm getting the following error message when executing the rollback method in a modelContext, what could be causing this ?
SwiftData/ModelSnapshot.swift:46: Fatal error: A ModelSnapshot must be initialized with a known-keys dictionary
The stuff I've found by searching has confused me, so hopefully someone can help simplify it for me?
I have an app (I use it for logging which books I've given away), and I could either add a bunch of things to the app, or I could have another app (possibly a CLI tool) to generate some reports I'd like.
Hello,
I am trying to get the elements from my SwiftData databse in the configuration for my widget.
The SwiftData model is the following one:
@Model
class CountdownEvent {
@Attribute(.unique) var id: UUID
var title: String
var date: Date
@Attribute(.externalStorage) var image: Data
init(id: UUID, title: String, date: Date, image: Data) {
self.id = id
self.title = title
self.date = date
self.image = image
}
}
And, so far, I have tried the following thing:
AppIntent.swift
struct ConfigurationAppIntent: WidgetConfigurationIntent {
static var title: LocalizedStringResource { "Configuration" }
static var description: IntentDescription { "This is an example widget." }
// An example configurable parameter.
@Parameter(title: "Countdown")
var countdown: CountdownEntity?
}
Countdowns.swift, this is the file with the widget view
struct Provider: AppIntentTimelineProvider {
func placeholder(in context: Context) -> SimpleEntry {
SimpleEntry(date: Date(), configuration: ConfigurationAppIntent())
}
func snapshot(for configuration: ConfigurationAppIntent, in context: Context) async -> SimpleEntry {
SimpleEntry(date: Date(), configuration: configuration)
}
func timeline(for configuration: ConfigurationAppIntent, in context: Context) async -> Timeline<SimpleEntry> {
var entries: [SimpleEntry] = []
// Generate a timeline consisting of five entries an hour apart, starting from the current date.
let currentDate = Date()
for hourOffset in 0 ..< 5 {
let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
let entry = SimpleEntry(date: entryDate, configuration: configuration)
entries.append(entry)
}
return Timeline(entries: entries, policy: .atEnd)
}
// func relevances() async -> WidgetRelevances<ConfigurationAppIntent> {
// // Generate a list containing the contexts this widget is relevant in.
// }
}
struct SimpleEntry: TimelineEntry {
let date: Date
let configuration: ConfigurationAppIntent
}
struct CountdownsEntryView : View {
var entry: Provider.Entry
var body: some View {
VStack {
Text("Time:")
Text(entry.date, style: .time)
Text("Title:")
Text(entry.configuration.countdown?.title ?? "Default")
}
}
}
struct Countdowns: Widget {
let kind: String = "Countdowns"
var body: some WidgetConfiguration {
AppIntentConfiguration(kind: kind, intent: ConfigurationAppIntent.self, provider: Provider()) { entry in
CountdownsEntryView(entry: entry)
.containerBackground(.fill.tertiary, for: .widget)
}
}
}
CountdownEntity.swift, the file for the AppEntity and EntityQuery structs
struct CountdownEntity: AppEntity, Identifiable {
var id: UUID
var title: String
var date: Date
var image: Data
var displayRepresentation: DisplayRepresentation {
DisplayRepresentation(title: "\(title)")
}
static var defaultQuery = CountdownQuery()
static var typeDisplayRepresentation: TypeDisplayRepresentation = "Countdown"
init(id: UUID, title: String, date: Date, image: Data) {
self.id = id
self.title = title
self.date = date
self.image = image
}
init(id: UUID, title: String, date: Date) {
self.id = id
self.title = title
self.date = date
self.image = Data()
}
init(countdown: CountdownEvent) {
self.id = countdown.id
self.title = countdown.title
self.date = countdown.date
self.image = countdown.image
}
}
struct CountdownQuery: EntityQuery {
typealias Entity = CountdownEntity
static var typeDisplayRepresentation = TypeDisplayRepresentation(name: "Countdown Event")
static var defaultQuery = CountdownQuery()
@Environment(\.modelContext) private var modelContext // Warning here: Stored property '_modelContext' of 'Sendable'-conforming struct 'CountdownQuery' has non-sendable type 'Environment<ModelContext>'; this is an error in the Swift 6 language mode
func entities(for identifiers: [UUID]) async throws -> [CountdownEntity] {
let countdownEvents = getAllEvents(modelContext: modelContext)
return countdownEvents.map { event in
return CountdownEntity(id: event.id, title: event.title, date: event.date, image: event.image)
}
}
func suggestedEntities() async throws -> [CountdownEntity] {
// Return some suggested entities or an empty array
return []
}
}
CountdownsManager.swift, this one just has the function that gets the array of countdowns
func getAllEvents(modelContext: ModelContext) -> [CountdownEvent] {
let descriptor = FetchDescriptor<CountdownEvent>()
do {
let allEvents = try modelContext.fetch(descriptor)
return allEvents
}
catch {
print("Error fetching events: \(error)")
return []
}
}
I have installed it in my phone and when I try to edit the widget, it doesn't show me any of the elements I have created in the app, just a loading dropdown for half a second:
What am I missing here?
Topic:
App & System Services
SubTopic:
Widgets & Live Activities
Tags:
SwiftUI
WidgetKit
App Intents
SwiftData
Hello,
SwiftData is not working correctly with Swift Concurrency. And it’s sad after all this time.
I personally found a regression. The attached code works perfectly fine on iOS 17.5 but doesn’t work correctly on iOS 18 or iOS 18.1.
A model can be updated from the background (Task, Task.detached or ModelActor) and refreshes the UI, but as soon as the same item is updated from the View (fetched via a Query), the next background updates are not reflected anymore in the UI, the UI is not refreshed, the updates are not merged into the main.
How to reproduce:
Launch the app
Tap the plus button in the navigation bar to create a new item
Tap on the “Update from Task”, “Update from Detached Task”, “Update from ModelActor” many times
Notice the time is updated
Tap on the “Update from View” (once or many times)
Notice the time is updated
Tap again on “Update from Task”, “Update from Detached Task”, “Update from ModelActor” many times
Notice that the time is not update anymore
Am I doing something wrong? Or is this a bug in iOS 18/18.1?
Many other posts talk about issues where updates from background thread are not merged into the main thread. I don’t know if they all are related but it would be nice to have
1/ bug fixed, meaning that if I update an item from a background, it’s reflected in the UI, and
2/ proper documentation on how to use SwiftData with Swift Concurrency (ModelActor). I don’t know if what I’m doing in my buttons is correct or not.
Thanks,
Axel
import SwiftData
import SwiftUI
@main
struct FB_SwiftData_BackgroundApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.modelContainer(for: Item.self)
}
}
}
struct ContentView: View {
@Environment(\.modelContext) private var modelContext
@State private var simpleModelActor: SimpleModelActor!
@Query private var items: [Item]
var body: some View {
NavigationView {
VStack {
if let firstItem: Item = items.first {
Text(firstItem.timestamp, format: Date.FormatStyle(date: .omitted, time: .standard))
.font(.largeTitle)
.fontWeight(.heavy)
Button("Update from Task") {
let modelContainer: ModelContainer = modelContext.container
let itemID: Item.ID = firstItem.persistentModelID
Task {
let context: ModelContext = ModelContext(modelContainer)
guard let itemInContext: Item = context.model(for: itemID) as? Item else { return }
itemInContext.timestamp = Date.now.addingTimeInterval(.random(in: 0...2000))
try context.save()
}
}
.buttonStyle(.bordered)
Button("Update from Detached Task") {
let container: ModelContainer = modelContext.container
let itemID: Item.ID = firstItem.persistentModelID
Task.detached {
let context: ModelContext = ModelContext(container)
guard let itemInContext: Item = context.model(for: itemID) as? Item else { return }
itemInContext.timestamp = Date.now.addingTimeInterval(.random(in: 0...2000))
try context.save()
}
}
.buttonStyle(.bordered)
Button("Update from ModelActor") {
let container: ModelContainer = modelContext.container
let persistentModelID: Item.ID = firstItem.persistentModelID
Task.detached {
let actor: SimpleModelActor = SimpleModelActor(modelContainer: container)
await actor.updateItem(identifier: persistentModelID)
}
}
.buttonStyle(.bordered)
Button("Update from ModelActor in State") {
let container: ModelContainer = modelContext.container
let persistentModelID: Item.ID = firstItem.persistentModelID
Task.detached {
let actor: SimpleModelActor = SimpleModelActor(modelContainer: container)
await MainActor.run {
simpleModelActor = actor
}
await actor.updateItem(identifier: persistentModelID)
}
}
.buttonStyle(.bordered)
Divider()
.padding(.vertical)
Button("Update from View") {
firstItem.timestamp = Date.now.addingTimeInterval(.random(in: 0...2000))
}
.buttonStyle(.bordered)
} else {
ContentUnavailableView(
"No Data",
systemImage: "slash.circle", //
description: Text("Tap the plus button in the toolbar")
)
}
}
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button(action: addItem) {
Label("Add Item", systemImage: "plus")
}
}
}
}
}
private func addItem() {
modelContext.insert(Item(timestamp: Date.now))
try? modelContext.save()
}
}
@ModelActor
final actor SimpleModelActor {
var context: String = ""
func updateItem(identifier: Item.ID) {
guard let item = self[identifier, as: Item.self] else {
return
}
item.timestamp = Date.now.addingTimeInterval(.random(in: 0...2000))
try! modelContext.save()
}
}
@Model
final class Item: Identifiable {
var timestamp: Date
init(timestamp: Date) {
self.timestamp = timestamp
}
}
Here’s the situation:
• You’re downloading a huge list of data from iCloud.
• You’re saving it one by one (sequentially) into SwiftData.
• You don’t want the SwiftUI view to refresh until all the data is imported.
• After all the import is finished, SwiftUI should show the new data.
The Problem
If you insert into the same ModelContext that SwiftUI’s @Environment(.modelContext) is watching, each insert may cause SwiftUI to start reloading immediately.
That will make the UI feel slow, and glitchy, because SwiftUI will keep trying to re-render while you’re still importing.
How to achieve this in Swift Data ?
Hi all,
I am using SwiftData and cloudkit and I am having an extremely persistent bug.
I am building an education section on a app that's populated with lessons via a local JSON file. I don't need this lesson data to sync to cloudkit as the lessons are static, just need them imported into swiftdata so I've tried to use the modelcontainer like this:
static func createSharedModelContainer() -> ModelContainer {
// --- Define Model Groups ---
let localOnlyModels: [any PersistentModel.Type] = [
Lesson.self, MiniLesson.self,
Quiz.self, Question.self
]
let cloudKitSyncModels: [any PersistentModel.Type] = [
User.self, DailyTip.self, UserSubscription.self,
UserEducationProgress.self // User progress syncs
]
However, what happens is that I still get Lesson and MiniLesson record types on cloudkit and for some reason as well, whenever I update the data models or delete and reinstall the app on simulator, the lessons duplicate (what seems to happen is that a set of lessons comes from the JSON file as it should), and then 1-2 seconds later, an older set of lessons gets synced from cloudkit.
I can delete the old set of lessons if I just delete the lessons and mini lessons record types, but if I update the data model again, this error reccurrs.
Sorry, I don't know if I managed to explain this well but essentially I just want to stop the lessons and minilessons from being uploaded to cloudkit as I think this will fix the problem. Am I doing something wrong with the code?
In a document based SwiftData app for macOS, how do you go about opening a (modal) child window connected to the ModelContainer of the currently open document?
Using .sheet() does not really result in a good UX, as the appearing view lacks the standard window toolbar.
Using a separate WindowGroup with an argument would achieve the desired UX. However, as WindowGroup arguments need to be Hashable and Codable, there is no way to pass a ModelContainer or a ModelContext there:
WindowGroup(id: "myWindowGroup", for: MyWindowGroupArguments.self) { $args in
ViewThatOpensInAWindow(args: args)
}
Is there any other way?
I have a document based SwiftData app in which I would like to implement a persistent cache. For obvious reasons, I would not like to store the contents of the cache in the documents themselves, but in my app's data directory.
Is a use case, in which a document based SwiftData app uses not only the ModelContainers from the currently open files, but also a ModelContainer writing a database file in the app's documents directory (for cache, settings, etc.) supported?
If yes, how can you inject two different ModelContexts, one tied to the currently open file and one tied to the local database, into a SwiftUI view?
Hi all,
has anybody found the trick how to get SwiftData working with SpotLight Search?
Setting the attribute "spotlight" in the Model definition seems to do nothing at all, as pointed out by Paul Hudson in his new book as well
(https://www.hackingwithswift.com/quick-start/swiftdata/how-to-index-swiftdata-objects-in-spotlight)
Thanks a lot!
Hi,
I am currently developing a document-based application for macOS and have encountered a challenge related to document container management. Specifically, I need to open a windowGroup that shares the same container as the one used in the DocumentGroup. However, my current approach of using a global shared model container has led to unintended behavior: any new document created is linked to existing ones, and changes made in one document are reflected across all documents.
To address this issue, I am looking for a solution that allows each newly created document to be individualized while still sharing the document container with all relevant WindowGroups that require access to the data it holds. I would greatly appreciate any insights or recommendations you might have on how to achieve this.
Thank you for your time and assistance.
Best regards,
Something like:
@main
struct Todo: App {
var body: some Scene {
DocumentGroup(editing: Item.self, contentType: .item) {
ContentView()
}
WindowGroup {
UndockView()
.modelContainer(of documentGroup above)
}
}
}
Hello,
I am building a pretty large database (~40MB) to be used in my SwiftData iOS app as read-only.
While inserting and updating the data, I noticed a substantial increase in size (+ ~10MB).
A little digging pointed to ACHANGE and ATRANSACTION tables that apparently are dealing with Persistent History Tracking.
While I do appreciate the benefits of that, I prefer to save space.
Could you please point me in the right direction?