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?
iCloud & Data
RSS for tagLearn how to integrate your app with iCloud and data frameworks for effective data storage
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I've noticed that SwiftData's @Relationship seems to potentially cause application crashes.
The crash error is shown in the image.
Since this crash appears to be random and I cannot reproduce it under specific circumstances, I can only temporarily highlight that this issue seems to exist.
@Model final class TrainInfo {
@Relationship(deleteRule: .cascade, inverse: \StopStation.trainInfo)
var stations: [StopStation]?
}
@Model final class StopStation {
@Relationship
var trainInfo: TrainInfo?
}
/// some View
var origin: StopStationDisplayable? {
if let train = train as? TrainInfo {
return train.stations?.first(where: { $0.isOrigin }) ?? train.stations?.first(where: { $0.isStarting })
}
return nil
}
// Some other function or property
func someFunction() {
if let origin, let destination {
// Function implementation
}
}
About 4 months ago, I shipped the first version of my app with 4 versioned schemas that, unintentionally, had the same versionIdentifier of 1.2.0 in 2 of them:
V1: 1.0.0
V2: 1.1.0
V3: 1.2.0
V4: 1.2.0
They are ordered correctly in the MigrationPlan, and they are all lightweight.
Migration works, SwiftData doesn't crash on init and I haven't encountered any issues related to this. The app syncs with iCloud.
Questions, preferable for anybody with knowledge of SwiftData internals:
What will break in SwiftData when there are 2 duplicate numbers?
Not that I would expect it to be safe, but does it happen to be safe to ship an update that changes V4's version to 1.3.0, what was originally intended?
Topic:
App & System Services
SubTopic:
iCloud & Data
I am working with SwiftData and get the below error. I can't find any documentation on it to see what to fix. Any help would be appreciated.
Fatal error: This relationship already has a value but it's not the target:
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.
I have made a Swift App for MacOS 15 under XCode 16.3, which runs fine. I also want to run it under the previous MacOS 14. Unfortunately it crashes without even starting up (it does not even reach the first log output statement on the first view)
The crash reason is
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Exception Type: EXC_BAD_INSTRUCTION (SIGILL)
Exception Codes: 0x0000000000000001, 0x0000000000000000
Termination Reason: Namespace SIGNAL, Code 4 Illegal instruction: 4
Terminating Process: exc handler [2970]
I have set the miminium deployment to MacOS 14.0 but to no effect. The XCode machine is a MacOS 15.4 on Arm M3 and the target machine is MacOS 14.7.5 on Intel (MacBook Air)
I think it might be related to the compiler and linker settings.
Hi, I am building an iOS app with SwiftUI and SwiftData for the first time and I am experiencing a lot of difficulty with this error:
Thread 44: Fatal error: Never access a full future backing data - PersistentIdentifier(id: SwiftData.PersistentIdentifier.ID(backing: SwiftData.PersistentIdentifier.PersistentIdentifierBacking.managedObjectID(<ID> <x-coredata://<UUID>/MySwiftDataModel/p1>)), backing: SwiftData.PersistentIdentifier.PersistentIdentifierBacking.managedObjectID(<ID> <x-coredata://<UUID>/MySwiftDataModel/p1>)) with Optional(<UUID>)
I have been trying to figure out what the problem is, but unfortunately I cannot find any information in the documentation or on other sources online. My only theory about this error is that it is somehow related to fetching an entity that has been created in-memory, but not yet saved to the modelContext in SwiftData.
However, when I am trying to debug this, it's not clear this is the case. Sometimes the error happens, sometimes it doesn't. Saving manually does not always solve the error.
Therefore, it would be extremely helpful if someone could explain what this error means and whether there are any best practices to do with SwiftData, or some pitfalls to avoid (such as wrapping my model context into a repository class).
To be clear, this problem is NOT related to one area of my code, it happens throughout my app, at unpredictable places and time. Given that there is very little information related to this error, I am at a loss at how to make sure that this never happens.
This question has been asked on the forum here as well as on StackOverflow, Reddit (can't link that here), but none of the answers worked for me.
For reference, my models generally look like this:
import Foundation
import SwiftData
@Model
final class MySwiftDataModel {
// Stable cross-device identity
@Attribute(.unique)
var uuid: UUID
var someNumber: Int
var someString: String
@Relationship(deleteRule: .nullify, inverse: \AnotherSwiftDataModel.parentModel)
var childModels: [AnotherSwiftDataModel]
init(uuid: UUID = UUID(), someNumber: Int = 1, someString: String = "Some", childModels: [AnotherSwiftDataModel] = []) {
self.uuid = uuid
self.someNumber = someNumber
self.someString = someString
self.childModels = childModels
}
func addChildModel(model: AnotherSwiftDataModel) {
self.childModels.append(model)
}
func removeChildModel(by id: PersistentIdentifier) {
self.childModels = self.childModels.filter { $0.id != id }
}
}
and the child model:
import Foundation
import SwiftData
@Model
final class AnotherSwiftDataModel {
// Stable cross-device identity
@Attribute(.unique)
var uuid: UUID
var someNumber: Int
var someString: String
var parentModel: MySwiftDataModel?
init(uuid: UUID = UUID(), someNumber: Int = 1, someString: String = "Some") {
self.uuid = uuid
self.someNumber = someNumber
self.someString = someString
}
}
For now, you can assume I am not using CloudKit - i know for a fact the error is unrelated to CloudKit, because it happens when I am not using CloudKit (so I do not need to follow CloudKit's requirements for model design, such as nullable values etc).
As I said, the error surfaces at different times - sometimes during assignments, a lot of times during deletions of related models, etc.
Could you please explain what I am doing wrong and how I can make sure that this error does not happen? What are the architectural patterns that work best for SwiftData in this case? Do you have any examples of things I should avoid?
Thanks
We're in the process of migrating our app to the Swift 6 language mode. I have hit a road block that I cannot wrap my head around, and it concerns Core Data and how we work with NSManagedObject instances.
Greatly simplied, our Core Data stack looks like this:
class CoreDataStack {
private let persistentContainer: NSPersistentContainer
var viewContext: NSManagedObjectContext { persistentContainer.viewContext }
}
For accessing the database, we provide Controller classes such as e.g.
class PersonController {
private let coreDataStack: CoreDataStack
func fetchPerson(byName name: String) async throws -> Person? {
try await coreDataStack.viewContext.perform {
let fetchRequest = NSFetchRequest<Person>()
fetchRequest.predicate = NSPredicate(format: "name == %@", name)
return try fetchRequest.execute().first
}
}
}
Our view controllers use such controllers to fetch objects and populate their UI with it:
class MyViewController: UIViewController {
private let chatController: PersonController
private let ageLabel: UILabel
func populateAgeLabel(name: String) {
Task {
let person = try? await chatController.fetchPerson(byName: name)
ageLabel.text = "\(person?.age ?? 0)"
}
}
}
This works very well, and there are no concurrency problems since the managed objects are fetched from the view context and accessed only in the main thread.
When turning on Swift 6 language mode, however, the compiler complains about the line calling the controller method:
Non-sendable result type 'Person?' cannot be sent from nonisolated context in call to instance method 'fetchPerson(byName:)'
Ok, fair enough, NSManagedObject is not Sendable. No biggie, just add @MainActor to the controller method, so it can be called from view controllers which are also main actor. However, now the compiler shows the same error at the controller method calling viewContext.perform:
Non-sendable result type 'Person?' cannot be sent from nonisolated context in call to instance method 'perform(schedule:_:)'
And now I'm stumped. Does this mean NSManageObject instances cannot even be returned from calls to NSManagedObjectContext.perform? Ever? Even though in this case, @MainActor matches the context's actor isolation (since it's the view context)?
Of course, in this simple example the controller method could just return the age directly, and more complex scenarios could return Sendable data structures that are instantiated inside the perform closure. But is that really the only legal solution? That would mean a huge refactoring challenge for our app, since we use NSManageObject instances fetched from the view context everywhere. That's what the view context is for, right?
tl;dr: is it possible to return NSManagedObject instances fetched from the view context with Swift 6 strict concurrency enabled, and if so how?
Hi there
We're using CloudKit in our app which, generally, syncs data perfectly between devices. However, recently the sync has stopped working (some changes will never sync and the sync is delayed for several days even with the app open on all devices). CloudKit's logs show the error „You can't save and delete the same record" and „Already have a mirrored relationship registered for this key", etc. We’ve a hunch that this issue is related to a mirrored relationship of one database entity.
Our scenario:
We've subclassed the database entities.
The database model (which we can't share publicly) contains mirrored relationships.
We store very long texts in the database (similar to a Word document that contains markup data – in case that’s relevant).
Deleting all data and starting with a completely new container and bundle identifier didn’t help (we tried that multiple times).
This issue occurs on macOS (15.2(24C101) as well on iOS (18.2).
Any hints on how to get the sync working again? Should we simply avoid mirrored relationships?
Many thanks
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?
Hi. I am having this error when trying to write to CloudKit public database.
<CKError 0x600000dbc4e0: "Permission Failure" (10/2007); server message = "Invalid bundle ID for container";
On app launch, I check for account status and ensure that the correct bundle identifier and container is being used. When the account status is checked, I do get the correct bundle id and container id printed in the console but trying to read or write to the container would throw that "Invalid bundle ID for container" error.
private init() {
container = CKContainer.default()
publicDB = container.publicCloudDatabase
// Check iCloud account status
checkAccountStatus()
}
func checkAccountStatus() {
print("🔍 CloudKit Debug:")
print("🔍 Bundle identifier from app: (Bundle.main.bundleIdentifier ?? "unknown")")
print("🔍 Container identifier: (container.containerIdentifier ?? "unknown")")
container.accountStatus { [weak self] status, error in
DispatchQueue.main.async {
switch status {
case .available:
self?.isSignedIn = true
self?.fetchUserID()
case .noAccount, .restricted, .couldNotDetermine:
self?.isSignedIn = false
self?.errorMessage = "Please sign in to iCloud in Settings to use this app."
default:
self?.isSignedIn = false
self?.errorMessage = "Unknown iCloud account status."
}
print("User is signed into iCloud: \(self?.isSignedIn ?? false)")
print("Account status: \(status.rawValue)")
}
}
}
I have tried:
Creating a new container
Unselecting and selecting the container in signing & capabilities
Unselecting and selecting the container in App ID Configuration
I used to have swift data models in my code and read that swift data is not compatible with CloudKit public data so I removed all the models and any swift data codes and only uses CloudKit public database.
let savedRecord = try await publicDB.save(record)
Nothing seems to work. If anyone could help please?
Rgds,
Hans
Topic:
App & System Services
SubTopic:
iCloud & Data
Tags:
CloudKit
Cloud and Local Storage
CloudKit Console
I'm beta-testing a CloudKit-based app. One of my testers suddenly reported that they got a .badContainer CloudKit error:
<CKError 0x302619800:"Bad Container" (5/1014); server message = "Invalid container to get bundle ids"; op = <...>; uuid = <...>; container ID = "<...>">
(all private info replaced with <...>)
The container ID in the message was exactly what I expected, and exactly what other users are successfully using.
When I followed up on the report, the user said she tried again later and everything was fine. It's still working fine days later.
What could cause a user to get a .badContainer message, when all other users using the same app are fine, the container ID makes sense, and future runs work fine?
Is this something I need to worry about? Does it maybe sometimes happen when CloudKit is having some kind of outage?
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'm experiencing a critical issue with SwiftData custom migrations where objects created during migration appear to be inserted successfully but aren't persisted or found by queries after migration completes. The migration logs show objects being created, but subsequent queries return zero results.
I'm migrating from schema version V2 to V2_5, which involves:
Renaming Person class to GroupData
Keeping the same data structure but changing the class name while keeping the old class.
Using a custom migration stage to copy data from old to new schema
Below is an extract of my two schema and migration plan:
Environment:
Xcode 16.0,
iOS 18.0,
Swift 6.0
SchemaV2
enum LinkMapV2: VersionedSchema {
static let versionIdentifier: Schema.Version = .init(2, 0, 0)
static var models: [any PersistentModel.Type] {
[AnnotationData.self, Person.self, History.self]
}
@Model
final class Person {
@Attribute(.unique) var id: UUID
var name: String
var photo: String
var requirement: String
var statue: Bool
var annotationId: UUID?
var number: Int = 0
init(id: UUID = UUID(), name: String = "", photo: String = "", requirement: String = "", status: Bool = false, annotationId: UUID? = nil, number: Int = 0) {
self.id = id
self.name = name
self.photo = photo
self.requirement = requirement
self.statue = status
self.annotationId = annotationId
self.number = number
}
}
}
Schema V2_5
static let versionIdentifier: Schema.Version = .init(2, 5, 0)
static var models: [any PersistentModel.Type] {
[AnnotationData.self, Person.self, GroupData.self, History.self]
}
// Keep the old Person model for migration
@Model
final class Person {
@Attribute(.unique) var id: UUID
var name: String
var photo: String
var requirement: String
var statue: Bool
var annotationId: UUID?
var number: Int = 0
init(id: UUID = UUID(), name: String = "", photo: String = "", requirement: String = "", status: Bool = false, annotationId: UUID? = nil, number: Int = 0) {
self.id = id
self.name = name
self.photo = photo
self.requirement = requirement
self.statue = status
self.annotationId = annotationId
self.number = number
}
}
// Add the new GroupData model that mirrors Person
@Model
final class GroupData {
@Attribute(.unique) var id: UUID
var name: String
var photo: String
var requirement: String
var status: Bool
var annotationId: UUID?
var number: Int = 0
init(id: UUID = UUID(), name: String = "", photo: String = "", requirement: String = "", status: Bool = false, annotationId: UUID? = nil, number: Int = 0) {
self.id = id
self.name = name
self.photo = photo
self.requirement = requirement
self.status = status
self.annotationId = annotationId
self.number = number
}
}
}
Migration Plan
static let migrationV2toV2_5 = MigrationStage.custom(
fromVersion: LinkMapV2.self,
toVersion: LinkMapV2_5.self,
willMigrate: { context in
do {
let persons = try context.fetch(FetchDescriptor<LinkMapV2.Person>())
print("=== MIGRATION STARTED ===")
print("Found \(persons.count) Person objects to migrate")
guard !persons.isEmpty else {
print("No Person data requires migration")
return
}
for person in persons {
print("Migrating Person: '\(person.name)' with ID: \(person.id)")
let newGroup = LinkMapV2_5.GroupData(
id: person.id, // Keep the same ID
name: person.name,
photo: person.photo,
requirement: person.requirement,
status: person.statue,
annotationId: person.annotationId,
number: person.number
)
context.insert(newGroup)
print("Inserted new GroupData: '\(newGroup.name)'")
// Don't delete the old Person yet to avoid issues
// context.delete(person)
}
try context.save()
print("=== MIGRATION COMPLETED ===")
print("Successfully migrated \(persons.count) Person objects to GroupData")
} catch {
print("=== MIGRATION ERROR ===")
print("Migration failed with error: \(error)")
}
},
didMigrate: { context in
do {
// Verify migration in didMigrate phase
let groups = try context.fetch(FetchDescriptor<LinkMapV2_5.GroupData>())
let oldPersons = try context.fetch(FetchDescriptor<LinkMapV2_5.Person>())
print("=== MIGRATION VERIFICATION ===")
print("New GroupData count: \(groups.count)")
print("Remaining Person count: \(oldPersons.count)")
// Now delete the old Person objects
for person in oldPersons {
context.delete(person)
}
if !oldPersons.isEmpty {
try context.save()
print("Cleaned up \(oldPersons.count) old Person objects")
}
// Print all migrated groups for debugging
for group in groups {
print("Migrated Group: '\(group.name)', Status: \(group.status), Number: \(group.number)")
}
} catch {
print("Migration verification error: \(error)")
}
}
)
And I've attached console output below:
Console Output
After Xcode 26.1 was updated and installing the OS 26.1 simulators, my app started crashing related to transformable properties. When I checked my schema, I noticed that properties with array collection types are suddenly set with an option transformable with Optional("NSSecureUnarchiveFromData")], even though I do not use any transformable types. I verified the macros, no transformable was specified. This is causing ModelCoders to encode/decode my properties incorrectly.
This is not an issue when I switch back to OS 26.0 simulators.
I've noticed several crashes that look like they're caused by an index out of bound in internal methods of NSFetchedResultsController. This happens while changes are merged from the persistent store container into the view context. Here's an example of the last exception backtrace.
Exactly which internal methods that are called in - [NSFetchedResultsController(PrivateMethods) _core_managedObjectContextDidChange:] vary between crash reports but they all end up crashing from _NSArrayRaiseBoundException.
The Core Data stack consists of one persistent store, one persistent store coordinator that the view context is set up to automatically merge changes from, and data is saved to disk from background context.
persistentContainer.loadPersistentStores(...)
viewContext = persistentContainer.viewContext
viewContext.automaticallyMergesChangesFromParent = true
backgroundContext = persistentContainer.newBackgroundContext()
backgroundContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
backgroundClientContext = persistentContainer.newBackgroundContext()
backgroundClientContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
Does anyone have any ideas what could be causing this? Thankful for any ideas or advice on how to investigate further.
Hi,
I’m completely stuck with a very strange CloudKit problem that started recently and has now killed all iCloud sync for a live production app.
What is happening
Production container: iCloud.gainzCloud (created ~11 months ago, has been working perfectly until now)
In Xcode 26.0 (17A321):
→ Signing & Capabilities → iCloud is enabled
→ Container correctly shows as iCloud.gainzCloud
→ App builds and runs on device/simulator with zero provisioning or container errors
CloudKit Dashboard (https://icloud.developer.apple.com/dashboard/): completely blank – “No containers found”
Result: CloudKit sync is dead for every user (development + production environments)
What I know for sure
Apple Developer Support confirmed the container iCloud.gainzCloud still exists and is correctly attached to my Team ID on their backend
Personal iCloud (Mail, Notes, Photos, etc.) syncs perfectly on the same Mac / same Apple ID under macOS Tahoe 26.1
I have NOT changed the password on either the Apple ID or the Developer Program account
New containers I create appear in Xcode but never show up in the Dashboard
Environment
macOS Tahoe 26.1 (latest)
Xcode Version 26.0 (17A321)
Has anyone on the new Tahoe/Xcode 26 releases seen the CloudKit Dashboard suddenly go completely empty while Xcode still “sees” the container just fine?
Any known trick to force the dashboard to re-index containers or clear whatever cache is broken?
Thanks a lot in advance – this is blocking all iCloud functionality for a released app with active users.
Topic:
App & System Services
SubTopic:
iCloud & Data
I am trying to implement record sharing in my project, but when I try to copy the link on the UICloudSharingController, the sheet closes and the link doesn't get copied.
My CloudKitManager function:
public func shareTeam(_ team: Team) -> AnyPublisher<CKShare, Error> {
Future { [weak self] promise in
guard let self = self else {
promise(.failure(CloudKitError.unknown))
return
}
let record = team.toCKRecord()
let share = CKShare(rootRecord: record)
share[CKShare.SystemFieldKey.title] = "Join \(team.name)" as CKRecordValue
share.publicPermission = .readWrite
let operation = CKModifyRecordsOperation(recordsToSave: [record, share], recordIDsToDelete: nil)
operation.savePolicy = .ifServerRecordUnchanged
operation.qualityOfService = .userInitiated
operation.modifyRecordsResultBlock = { result in
switch result {
case .success:
promise(.success(share))
case .failure(let error):
promise(.failure(error))
}
}
self.privateDatabase.add(operation)
}
.eraseToAnyPublisher()
}
ViewModel function:
func shareTeam() {
guard let selectedTeam = selectedTeam else { return }
CloudKitManager.shared.shareTeam(selectedTeam)
.receive(on: DispatchQueue.main)
.sink { [weak self] completion in
switch completion {
case .finished:
break
case .failure(let error):
self?.didError = true
self?.error = error
}
} receiveValue: { share in
let sharePresenter = SharePresenter(
share: share,
container: CloudKitManager.shared.container,
teamName: selectedTeam.name,
rootRecord: selectedTeam.toCKRecord()
)
sharePresenter.presentShareSheet()
}
.store(in: &cancellables)
}
When deleting a SwiftData entity, I sometimes encounter the following error in a document based SwiftUI app:
Fatal error: Unexpected backing data for snapshot creation: SwiftData._FullFutureBackingData<MyEntityClass>
The deletion happens in a SwiftUI View and the code used to retrieve the entity is standard (the ModelContext is injected from the @Environment):
let myEntity = modelContext.model(for: entityIdToDelete)
modelContext.delete(myEntity)
Unfortunately, I haven't yet managed to isolate this any further in order to come up with a reproducible PoC.
Could you give me further information about what this error means?
I have two recordTypes in CloudKit: Author and Book. The Book records have their parent property set to an Author, enabling hierarchical record sharing (i.e., if an Author record is shared, the participant can see all books associated with that author in their shared database).
When syncing with CKSyncEngine, I was expecting handleFetchedRecordZoneChanges to deliver all Author records before their associated Book records. However, unless I’m missing something, the order appears to be random.
This randomness forces me to handle two codepaths in my app (opposed to just one) to replicate CloudKit references in my local persistency storage:
Book arrives before its Author → I store the Book but defer setting its parent reference until the corresponding Author arrives.
Author arrives before its Books → I can immediately set the parent reference when each Book arrives.
Is there a way to ensure that Author records always arrive before Book records when syncing with CKSyncEngine? Or is this behavior inherently unordered and I have to implement two codepaths?