I've spent a few months writing an app that uses SwiftData with inheritance. Everything worked well until I tried adding CloudKit support. To do so, I had to make all relationships optional, which exposed what appears to be a bug. Note that this isn't a CloudKit issue -- it happens even when CloudKit is disabled -- but it's due to the requirement for optional relationships.
In the code below, I get the following error on the second call to modelContext.save() when the button is clicked:
Could not cast value of type 'SwiftData.PersistentIdentifier' (0x1ef510b68) to 'SimplePersistenceIdentifierTest.Computer' (0x1025884e0).
I was surprised to find zero hit when Googling "Could not cast value of type 'SwiftData.PersistentIdentifier'".
Some things to note:
Calling teacher.computers?.append(computer) instead of computer.teacher = teacher results in the same error.
It only happens when Teacher inherits Person.
It only happens if modelContext.save() is called both times.
It works if the first modelContext.save() is commented out.
If the second modelContext.save()is commented out, the error occurs the second time the model context is saved (whether explicitly or implicitly).
Keep in mind this is a super simple repro written to generate on demand the error I'm seeing in a normal app. In my app, modelContext.save() must be called in some places to update the UI immediately, sometimes resulting in the error seconds later when the model context is saved automatically. Not calling modelContext.save() doesn't appear to be an option.
To be sure, I'm new to this ecosystem so I'd be thrilled if I've missed something obvious! Any thoughts are appreciated.
import Foundation
import SwiftData
import SwiftUI
struct ContentView: View {
@Environment(\.modelContext) var modelContext
var body: some View {
VStack {
Button("Do it") {
let teacher = Teacher()
let computer = Computer()
modelContext.insert(teacher)
modelContext.insert(computer)
try! modelContext.save()
computer.teacher = teacher
try! modelContext.save()
}
}
}
}
@Model
class Computer {
@Relationship(deleteRule: .nullify)
var teacher: Teacher?
init() {}
}
@Model
class Person {
init() {}
}
@available(iOS 26.0, macOS 26.0, *)
@Model
class Teacher: Person {
@Relationship(deleteRule: .nullify, inverse: \Computer.teacher)
public var computers: [Computer]? = []
override init() {
super.init()
}
}
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
When I used to do Migrations, I always used ETL and then push to a dev system to review/test before going production.
The migration support is SwiftData is fine for a little tweak.
I might as well just just use new schema and context and write the custom code than use the SwiftData migration support.
I want to use the Observations AsyncSequence on some SwiftData @Model instances to determine if internal calculations need to be done.
When a simple property is linked to the Observations it fires CONTINUOUSLY even though no change is made to the model property.
Also, when I try to observe a property which is a list of another @Model type the Observations sequence does not fire when I add or remove items.
I am hoping to use the async-algorithm's merge function so all the associated sequences can be combined since if any of the associated events should fire the calculation event.
Experiencing a crash that is only reproducible on TestFlight or AppStore version of the app, note this does not happen when running from Xcode.
I've isolated the problem to sort argument being added to @Query that fetches a model that sorts based on inherited property.
To reproduce:
@Model
class SuperModel {
var createdAt: Date = .now
}
@available(macOS 26.0, *)
@Model
class SubModel: SuperModel {
}
@Query(sort: \SubModel.createdAt, animation: .default) private var models: [SubModel]
This is probably super simple answer that I missed, but: I have an app that has a database; I'd like to create a second app (actually a CLI tool), and access the same database. Is that possible? And, if so, how? 😄
I have a SwiftData flashcard app which I am syncing with CloudKit using NSPersistentCloudKitContainer. While syncing itself is working perfectly, I have noticed a dramatic increase in the app size after enabling sync.
Specifically, without CloudKit, 15k flashcards results in the default.store file being about 4.5 MB. With CloudKit, default.store is about 67 MB. I have inspected the store and found that most of this increase is due to the ANSCKRECORDMETADATA table.
My question is, does implementing CloudKit normally cause this magnitude of increase in storage? If it doesn’t, is there something in my model, schema, implementation, etc. that could be causing it?
Below are two other posts describing a similar issue, but neither with a solution. I replied to the first one about a month ago. I then submitted this to Developer Technical Support, but was asked to post my question in the forums, so here it is.
Strange behavior with 100k+ records in NSPersistentCloudKitContainer
Huge increase in sqlite file size after adopting CloudKit
Hi everyone,
In the simple app below, I have a QueryView that has LazyVStack containing 100k TextField's that edit the item's content. The items are fetched with a @Query. On launch, the app will generate 100k items. Once created, when I press any of the TextField's , a severe hang happens, and every time I type a single character, it will cause another hang over and over again.
I looked at it in Instruments and it shows that the main thread is busy during the duration of the hang (2.31 seconds) updating QueryView. From the cause and effect graph, the update is caused by @Observable QueryController <Item>.(Bool).
Why does it take too long to recalculate the view, given that it's in a LazyVStack? (In other words, why is the hang duration directly proportional to the number of items?)
How to fix the performance of this app? I thought adding LazyVStack was all I need to handle the large dataset, but maybe I need to add a custom pagination with .fetchLimit on top of that? (I understand that ModelActor would be an alternative to @Query because it will make the database operations happen outside of the main thread which will fix this problem, but with that I will lose the automatic fetching of @Query.)
Thank you for the help!
import SwiftData
import SwiftUI
@main
struct QueryPerformanceApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.modelContainer(for: [Item.self], inMemory: true)
}
}
}
@Model
final class Item {
var name: String
init(name: String) {
self.name = name
}
}
struct ItemDetail: View {
@Bindable var item: Item
var body: some View {
TextField("Name", text: $item.name)
}
}
struct QueryView: View {
@Query private var items: [Item]
var body: some View {
ScrollView {
LazyVStack {
ForEach(items) { item in
VStack {
ItemDetail(item: item)
}
}
}
}
}
}
struct ContentView: View {
let itemCount = 100_000
@Environment(\.modelContext) private var context
@State private var isLoading = true
var body: some View {
Group {
if isLoading {
VStack(spacing: 16) {
ProgressView()
Text("Generating \(itemCount) items...")
}
} else {
QueryView()
}
}
.task {
for i in 1...itemCount {
context.insert(Item(name: "Item \(i)"))
}
try? context.save()
isLoading = false
}
}
}
Hi everyone,
I’m running into a breaking issue with SwiftData automatic CloudKit syncing on iOS 26, and I'm trying to determine if this is a known regression or a new configuration requirement I missed.
The Setup: My setup is extremely standard; I am using the default configuration exactly as described in Apple's documentation here: https://developer.apple.com/documentation/swiftdata/syncing-model-data-across-a-persons-devices
The schema is very simple:
A single @Model class.
No relationships.
The Issue: Prior to iOS 26, this exact app was successfully syncing data between devices and to iCloud without issues. Immediately after the iOS 26 update, syncing stopped completely.
I haven't changed any code, but when I check the CloudKit Console, I am seeing some BAD_REQUEST errors during sync attempts.
Since I am using the default SwiftData sync (and not manual CKRecord handling), I’m not sure how my client code could be triggering a bad request unless the schema requirements have changed under the hood.
Questions:
Has anyone else seen increased BAD_REQUEST errors with SwiftData on iOS 26?
Are there new entitlements or strict schema requirements introduced in iOS 26 that might cause a previously valid model to be rejected by CloudKit?
Any pointers or confirmations would be appreciated. Thanks!
I am using SwiftData with CloudKit to synchronize data across multiple devices, and I have encountered an issue: occasionally, abnormal sync behavior occurs between two devices (it does not happen 100% of the time—only some users have reported this problem). It seems as if synchronization between the two devices completely stops; no matter what operations are performed on one end, the other end shows no response.
After investigating, I suspect the issue might be caused by both devices simultaneously modifying the same field, which could lead to CloudKit's logic being unable to handle such conflicts and causing the sync to stall. Are there any methods to avoid or resolve this situation?
Of course, I’m not entirely sure if this is the root cause. Has anyone encountered a similar issue?
Hi,
I was testing the new iOS 18 behavior where NSPersistentCloudKitContainer wipes the local Core Data store if the user logs out of iCloud, for privacy purposes.
I ran the tests both with a Core Data + CloudKit app, and a simple one using SwiftData with CloudKit enabled. Results were identical in either case.
In my testing, most of the time, the feature worked as expected. When I disabled iCloud for my app, the data was wiped (consistent with say the Notes app, except if you disable iCloud it warns you that it'll remove those notes). When I re-enabled iCloud, the data appeared. (all done through the Settings app)
However, in scenarios when NSPersistentCloudKitContainer cannot immediately sync -- say due to rate throttling -- and one disables iCloud in Settings, this wipes the local data store and ultimately results in data loss.
This occurs even if the changes to the managed objects are saved (to the local store) -- it's simply they aren't synced in time.
It can be a little hard to reproduce the issue, especially since when you exit to the home screen from the app, it generally triggers a sync. To avoid this, I swiped up to the screen where you can choose which apps to close, and immediately closed mine. Then, you can disable iCloud, and run the app again (with a debugger is helpful). I once saw a message with something along the lines of export failed (for my record that wasn't synced), and unfortunately it was deleted (and never synced).
Perhaps before NSPersistentCloudKitContainer wipes the local store it ought to force sync with the cloud first?
Hello, I've a question about performance when trying to render lots of items coming from SwiftData via a @Query on a SwiftUI List. Here's my setup:
// Item.swift:
@Model final class Item: Identifiable {
var timestamp: Date
var isOptionA: Bool
init() {
self.timestamp = Date()
self.isOptionA = Bool.random()
}
}
// Menu.swift
enum Menu: String, CaseIterable, Hashable, Identifiable {
var id: String { rawValue }
case optionA
case optionB
case all
var predicate: Predicate<Item> {
switch self {
case .optionA: return #Predicate { $0.isOptionA }
case .optionB: return #Predicate { !$0.isOptionA }
case .all: return #Predicate { _ in true }
}
}
}
// SlowData.swift
@main
struct SlowDataApp: App {
var sharedModelContainer: ModelContainer = {
let schema = Schema([Item.self])
let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)
return try! ModelContainer(for: schema, configurations: [modelConfiguration])
}()
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(sharedModelContainer)
}
}
// ContentView.swift
struct ContentView: View {
@Environment(\.modelContext) private var modelContext
@State var selection: Menu? = .optionA
var body: some View {
NavigationSplitView {
List(Menu.allCases, selection: $selection) { menu in
Text(menu.rawValue).tag(menu)
}
} detail: {
DemoListView(selectedMenu: $selection)
}.onAppear {
// Do this just once
// (0..<15_000).forEach { index in
// let item = Item()
// modelContext.insert(item)
// }
}
}
}
// DemoListView.swift
struct DemoListView: View {
@Binding var selectedMenu: Menu?
@Query private var items: [Item]
init(selectedMenu: Binding<Menu?>) {
self._selectedMenu = selectedMenu
self._items = Query(filter: selectedMenu.wrappedValue?.predicate,
sort: \.timestamp)
}
var body: some View {
// Option 1: touching `items` = slow!
List(items) { item in
Text(item.timestamp.description)
}
// Option 2: Not touching `items` = fast!
// List {
// Text("Not accessing `items` here")
// }
.navigationTitle(selectedMenu?.rawValue ?? "N/A")
}
}
When I use Option 1 on DemoListView, there's a noticeable delay on the navigation. If I use Option 2, there's none. This happens both on Debug builds and Release builds, just FYI because on Xcode 16 Debug builds seem to be slower than expected: https://indieweb.social/@curtclifton/113273571392595819
I've profiled it and the SwiftData fetches seem blazing fast, the Hang occurs when accessing the items property from the List. Is there anything I'm overlooking or it's just as fast as it can be right now?
I'm building a SwiftUI app with SwiftData and want to centralize both query logic and related actions in a manager class. For example, let's say I have a reading app where I need to track the currently reading book across multiple views.
What I want to achieve:
@Observable
class ReadingManager {
let modelContext: ModelContext
// Ideally, I'd love to do this:
@Query(filter: #Predicate<Book> { $0.isCurrentlyReading })
var currentBooks: [Book] // ❌ But @Query doesn't work here
var currentBook: Book? {
currentBooks.first
}
func startReading(_ book: Book) {
// Stop current book if any
if let current = currentBook {
current.isCurrentlyReading = false
}
book.isCurrentlyReading = true
try? modelContext.save()
}
func stopReading() {
currentBook?.isCurrentlyReading = false
try? modelContext.save()
}
}
// Then use it cleanly in any view:
struct BookRow: View {
@Environment(ReadingManager.self) var manager
let book: Book
var body: some View {
Text(book.title)
Button("Start Reading") {
manager.startReading(book)
}
if manager.currentBook == book {
Text("Currently Reading")
}
}
}
The problem is @Query only works in SwiftUI views. Without the manager, I'd need to duplicate the same query in every view just to call these common actions.
Is there a recommended pattern for this? Or should I just accept query duplication across views as the intended SwiftUI/SwiftData approach?
Hello,
In my iOS/SwiftUI/SwiftData app, I want the user to be able to hit [Cancel] from editing in a detail screen and return to the previous screen without changes being saved.
I believed that setting autosaveEnabled to false and/or calling .rollback would prevent changes from being saved, unless/until I call .save() when the user clicks [Save], but this does not seem to be correct.
I set modelContext.autosaveEnabled = false and I call modelContext.rollback() when the user hits [Cancel], but any changes they made are not rolled back, but saved even if I don’t call save().
I have tried setting autosaveEnabled to false when I create the ModelContainer on a @MainActor function when the App starts, and in the detail/edit screen’s .onAppear(). I can see that .rollback is being called when the [Cancel] button is tapped. In all cases, any changes the user made before hitting [Cancel] are saved.
The Developer Documentation on autosaveEnabled includes this:
“The default value is false. SwiftData automatically sets this property to true for the model container’s mainContext."
I am working on the mainContext, but it appears that setting autosaveEnabled to false has no effect no matter where in the code I set it.
If someone sees what I am doing wrong, I’d sure appreciate the input. If this description doesn’t explain the problem well enough, I’ll develop a minimal focused example.
Hi all,
I’m trying to understand SwiftData’s runtime semantics around optional to-many relationships, especially in the context of CloudKit-backed models.
I ran into behavior that surprised me, and I’d like to confirm whether this is intended design or a potential issue / undocumented behavior.
Minimal example
import SwiftUI
import SwiftData
@Model
class Node {
var children: [Node]? = nil
var parent: Node? = nil
init(children: [Node]? = nil, parent: Node? = nil) {
self.children = children
self.parent = parent
print(self.children == nil)
}
}
struct ContentView: View {
var body: some View {
Button("Create") {
_ = Node(children: nil)
}
}
}
Observed behavior
If @Model is not used, children == nil prints true as expected.
If @Model is used, children == nil prints false.
Inspecting the macro expansion, it appears SwiftData initializes relationship storage using backing data placeholders and normalizes to-many relationships into empty collections at runtime, even when declared as optional.
CloudKit context
From the SwiftData + CloudKit documentation:
“The iCloud servers don’t guarantee atomic processing of relationship changes, so CloudKit requires all relationships to be optional.”
Because of this, modeling relationships as optional is required when syncing with CloudKit, even for to-many relationships.
This is why I’m hesitant to simply switch the model to a non-optional [Node] = [], even though that would match the observed runtime behavior.
Questions
Is it intentional that optional to-many relationships in SwiftData are never nil at runtime, and instead materialize as empty collections?
If so, is Optional<[Model]> effectively treated as [Model] for runtime access, despite being required for CloudKit compatibility?
Is the defaultValue: nil in the generated Schema.PropertyMetadata intended only for schema/migration purposes rather than representing a possible runtime state?
Is there a recommended modeling pattern for CloudKit-backed SwiftData models where relationships must be optional, but runtime semantics behave as non-optional?
I’m mainly looking to ensure I’m aligning with SwiftData’s intended design and not relying on behavior that could change or break with CloudKit sync.
Thanks in advance for any clarification!
CloudKit CKRecordZone Deletion Issue
Problem: CloudKit record zones deleted via CKDatabase.modifyRecordZones(deleting:) or CKModifyRecordZonesOperation are successfully
removed but then reappear. I suspect they are automatically reinstated by CloudKit sync, despite successful deletion confirmation.
Environment:
SwiftData with CloudKit integration
Custom CloudKit zones created for legacy zone-based sharing
Observed Behavior:
Create custom zone (e.g., "TestZone1") via CKDatabase.modifyRecordZones(saving:)
Copy records to zone for sharing purposes
Delete zone using any CloudKit deletion API - returns success, no errors
Immediate verification: Zone is gone from database.allRecordZones()
After SwiftData/CloudKit sync or app restart: Zone reappears
Reproduction:
Tested with three different deletion methods - all exhibit same behaviour:
modifyRecordZones(deleting:) async API
CKModifyRecordZonesOperation (fire-and-forget)
CKModifyRecordZonesOperation with result callbacks
Zone deletion succeeds, change tokens (used to track updates to shared records) cleaned up
But zones are restored presumably by CloudKit background sync
Expected: Deleted zones should remain deleted
Actual: Zones are reinstated, creating orphaned zones
Trying to support undo & redo in an app that utilizes Swift Data and as with anything other than provided simplistic Apple demo examples the experience is not great.
The problem:
Im trying to build functionality that allows users to add items to an item group, where item and item group have a many-to-many relationship e.g. item group can hold many items and items can appear in multiple groups.
When trying to do so with relatively simple setup of either adding or removing item group from items relationship array, I am pretty consistently met with a hard crash after performing undo & redo. Sometimes it works the first few undo & redos but 95% of the time would crash on the first one.
Could not cast value of type 'Swift.Optional<Any>' (0x20a676be0) to 'Swift.Array<App.CodableStructModel>' (0x207a2bc08).
Where CodableStructModel is a Codable Value type inside Item.
Adding and removing this relationship should be undoable & redoable as typical for Mac interaction and is "supported" by SwiftData by default, meaning that the developer has to actively either wholly opt out of undo support in their modelContainer setup or do it on a per action scale with the only thing I know of:
modelContext.processPendingChanges()
modelContext.undoManager?.disableUndoRegistration()
.....
modelContext.processPendingChanges()
modelContext.undoManager?.enableUndoRegistration()
General rant on SwiftData:
Random crashes, inconsistencies, random cryptic errors thrown by the debugger and general lack of production level stability.
Each update breaks something new and there is very little guidance and communication from the Swift Data team on how to adapt and more importantly consideration for developers that have adopted Swift Data.
If SwiftData is not ready for production, it would go a long way to clearly communicate that and mark it as Beta product.
Greetings my fellow engineers,
I use SwiftData in my iOS app. The schema is unversioned and consists of a single model. I've been modifying the model for almost two years now and relying on automatic database migrations. I had no problems for all that time, but now trying to add a property to the model or even remove a property from the model results in an error which seems like SwiftData is no longer capable of performing an automatic migration.
The log console has things like the following:
CoreData: error: NSUnderlyingError : Error Domain=NSCocoaErrorDomain Code=134190 "(null)" UserInfo={reason=Each property must have a unique renaming identifier}
CoreData: error: reason : Can't find or automatically infer mapping model for migration
CoreData: error: storeType: SQLite
CoreData: error: configuration: default
CoreData: annotation: options:
CoreData: annotation: NSMigratePersistentStoresAutomaticallyOption : 1
CoreData: annotation: NSInferMappingModelAutomaticallyOption : 1
CoreData: annotation: NSPersistentStoreRemoteChangeNotificationOptionKey : 1
CoreData: annotation: NSPersistentHistoryTrackingKey : 1
CoreData: error: <NSPersistentStoreCoordinator: 0x7547b5480>: Attempting recovery from error encountered during addPersistentStore: 0x753f8d800 Error Domain=NSCocoaErrorDomain Code=134140 "Persistent store migration failed, missing mapping model."
Have you ever encountered such an issue? What are my options?
Simple code like
struct ContentView: View {
@Query var items: [Item]
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, world!")
}
.padding()
}
}
causes UI Hierarchy crash, on Simulators, iPhone and Mac
I found no solution but use @State with fetch descriptor.
Hi,
I am implementing a premium feature in my app where CloudKit syncing is available only for "Pro" users.
The Workflow:
Free Users: I initialize the ModelContainer with cloudKitDatabase: .none so their data stays local.
Pro Upgrade: When a user purchases a subscription, I restart the container with cloudKitDatabase: .automatic to enable syncing.
The Problem:
If a user starts as "Free" (creates local data) and later upgrades to "Pro", the app crashes immediately upon launch with the following error:
Fatal error: Failed to create ModelContainer: SwiftDataError(_error: SwiftData.SwiftDataError._Error.loadIssueModelContainer, _explanation: nil)
It seems that SwiftData fails to load the existing data once the configuration changes to expect a CloudKit-backed store.
My Question:
Is there a supported way to "toggle" CloudKit on for an existing local dataset without causing this crash? I want the user's existing local data to start syncing once they pay, but currently, it just crashes.
My code:
import Foundation
import SwiftData
public enum DataModelEnum: String {
case task, calendar
public static let container: ModelContainer = {
let isSyncEnabled = UserDefaults.isProUser
let config = ModelConfiguration(
groupContainer: .identifier("group.com.yourcompany.myApp"),
cloudKitDatabase: isSyncEnabled ? .automatic : .none
)
do {
return try ModelContainer(for: TaskModel.self, CalendarModel.self, configurations: config)
} catch {
fatalError("Failed to create ModelContainer: \(error)")
}
}()
}
Topic:
App & System Services
SubTopic:
iCloud & Data
Tags:
CloudKit
Cloud and Local Storage
SwiftData
Is there a way to view the data saved when using swiftdata? Even after deleting all models, the storage space taken up by the app in Settings is too large.