Hi everyone!
I have an app on the App Store that uses Core Data as its data store. (It's called Count on Me: Tally Counter. Feel free to check it out.) One of the app's core feature is an interactive widget with a simple button. When the button is tapped, it's supposed to update the entity in the store.
My requirement is that the changes are then reflected with minimal latency in the main app and – ideally – also on other devices of the same iCloud user. And vice-versa: When an entity is updated in the app (or on another device where the same iCloud user is logged in), the widget that shows this entity should also refresh to reflect the changes.
I have read multiple articles, downloaded sample projects, searched Stackoverflow and the Apple developer forums, and tried to squeeze a solution out of AI, but couldn't figure out how to make this work reliably.
So I tried to reduce the core problem to a minimal example project. It has two issues that I cannot resolve:
When I update an entity in the app, the widget is immediately updated as intended (due to a call to WidgetCenter's reloadAllTimelines method). However, when I update the same entity from the interactive widget using the same app intent, the changes are not reflected in the main app.
For the widget and the app to use the same local data store, I need to enable App Groups in both targets and set a custom location for the store within the shared app group. So I specify a custom URL for the NSPersistentStoreDescription when setting up the Core Data stack. The moment I do this, iCloud sync breaks.
Issue no. 1 is far more important to me as I haven't officially enabled iCloud sync yet in my real app that's already on the App Store. But it would be wonderful to resolve issue no. 2 as well. Surely, there must be a way to synchronize changes to the source of truth triggered by interactive widget with other devices of the same iCloud user. Otherwise, the feature to talk to the main app and the feature to synchronize with iCloud would be mutually exclusive.
Some other developers I talked to have suggested that the widget should only communicate proposed changes to the main app and once the main app is opened, it processes these changes and writes them to the NSPersistentCloudKitContainer which then synchronizes across devices. This is not an option for me as it would result in a stale state and potential data conflicts with different devices. For example, when a user has the same widget on their iPhone and their iPad, taps a button on the iPhone widget, that change would not be reflected on the iPad widget until the user decides to open the app on the iPhone. At the same time, the user could tap the button multiple times on their iPad widget, resulting in a conflicting state on both devices. Thus, this approach is not a viable solution.
An answer to this question will be greatly appreciated. The whole code including the setup of the Core Data stack is included in the repository reference above. Thank you!
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
Hello,
I have a iOS app I was looking at porting to Mac.
I'm having an issue with both the Mac (Designed for iPad) and Mac Catalyst Destinations. I can't test Mac due to too many build issues.
I'm trying to assign a new NSManagedObject into a NSPersistentStore.
let object = MyObject(context: context)
context.assign(object, to: nsPersistentStore)
This works fine for iOS/iOS Simulator/iPhone/iPad. But on the Mac it's crashing with
FAULT: NSInvalidArgumentException: Can't assign an object to a store that does not contain the object's entity.; {
Thread 1: "Can't assign an object to a store that does not contain the object's entity."
I have a total of 100 asset packs associated with my app but I have archived 5 of them. Unfortunately I am now unable to upload any more asset packs (the reported error is "backgroundAsset limit reached -- This app has already reached the maximum number of active backgroundAssets. Maximum allowed is 100.") I assumed that archiving asset packs would make them inactive (and thus not count against the limit). This seems to not be the case and I'm not sure how I can upload new asset packs.
I'm trying to understand the terminology around forward vs backward references in CloudKit.
Say I have two record types:
User
LeaderboardScore (a score belongs to a user)
The score record stores a user reference:
score["user"] = CKRecord.Reference(
recordID: userRecordID,
action: .deleteSelf
)
So:
LeaderboardScore → User
The user record does not store any references to scores
From a data-model perspective:
Is this considered a forward reference (child → parent)?
Or a back reference, since the score is "pointing back" to its owner?
My use case is having leaderboard in my app and so i have created a user table to store all the users and a score table for saving the scores of each user of the app.
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.
Apple WTF? What did you do to all my Apps? none of them work in iOS26.1 (all worked in 26.0).
XCode simply says:
CoreData: error: addPersistentStoreWithType:configuration:URL:options:error: returned error NSCocoaErrorDomain (134140) *
SwiftData is supposed to do all these automatically 🤷🏻
I have a simple app that makes an HTTPS call to gather some JSON which I then parse and add to my SwiftData database. The app then uses a simple @Query in a view to get the data into a list.
on iOS 16 this works fine. No problems. But the same code on iOS 26 (targeting iOS 18.5) crashes after about 15 seconds of idle time after the list is populated. The error message is:
Could not cast value of type '__NSCFNumber' (0x1f31ee568) to 'NSString' (0x1f31ec718).
and occurs when trying to access ANY property of the list.
I have a stripped down version of the app that shows the crash available.
To replicate the issue:
open the project in Xcode 26
target any iOS 26 device or simulator
compile and run the project.
after the list is displayed, wait about 15 seconds and the app crashes.
It is also of note that if you try to run the app again, it will crash immediately, unless you delete the app from the device.
Any help on this would be appreciated.
Feedback number FB20295815 includes .zip file
Below is the basic code (without the data models)
The Best Seller List.Swift
import SwiftUI
import SwiftData
@main
struct Best_Seller_ListApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer (for: NYTOverviewResponse.self)
}
}
ContentView.Swift
import os.log
import SwiftUI
struct ContentView: View {
@Environment(\.modelContext) var modelContext
@State private var listEncodedName = String()
var body: some View {
NavigationStack () {
ListsView()
}
.task {
await getBestSellerLists()
}
}
func getBestSellerLists() async {
guard let url = URL(string: "https://api.nytimes.com/svc/books/v3/lists/overview.json?api-key=\(NYT_API_KEY)") else {
Logger.errorLog.error("Invalid URL")
return
}
do {
let decoder = JSONDecoder()
var decodedResponse = NYTOverviewResponse()
//decode the JSON
let (data, _) = try await URLSession.shared.data(from: url)
decoder.keyDecodingStrategy = .convertFromSnakeCase
decodedResponse = try decoder.decode(NYTOverviewResponse.self, from: data)
//remove any lists that don't have list_name_encoded. Fixes a bug in the data
decodedResponse.results!.lists = decodedResponse.results!.lists!.filter { $0.listNameEncoded != "" }
// sort the lists
decodedResponse.results!.lists!.sort { (lhs, rhs) -> Bool in
lhs.displayName < rhs.displayName
}
//delete any potential existing data
try modelContext.delete(model: NYTOverviewResponse.self)
//add the new data
modelContext.insert(decodedResponse)
} catch {
Logger.errorLog.error("\(error.localizedDescription)")
}
}
}
ListsView.Swift
import os.log
import SwiftData
import SwiftUI
@MainActor
struct ListsView: View {
//MARK: - Variables and Constants
@Query var nytOverviewResponses: [NYTOverviewResponse]
enum Updated: String {
case weekly = "WEEKLY"
case monthly = "MONTHLY"
}
//MARK: - Main View
var body: some View {
List {
if nytOverviewResponses.isEmpty {
ContentUnavailableView("No lists yet", systemImage: "list.bullet", description: Text("NYT Bestseller lists not downloaded yet"))
} else {
WeeklySection
MonthlySection
}
}
.navigationBarTitle("Bestseller Lists", displayMode: .large)
.listStyle(.grouped)
}
var WeeklySection: some View {
let rawLists = nytOverviewResponses.last?.results?.lists ?? []
// Build a value-typed array to avoid SwiftData faulting during sort
let weekly = rawLists
.filter { $0.updateFrequency == Updated.weekly.rawValue }
.map { (name: $0.displayName, encoded: $0.listNameEncoded, model: $0) }
.sorted { $0.name < $1.name }
return Section(header: Text("Weekly lists to be published on \(nytOverviewResponses.last?.results?.publishedDate ?? "-")")) {
ForEach(weekly, id: \.encoded) { item in
Text(item.name).font(Font.custom("Georgia", size: 17))
}
}
}
var MonthlySection: some View {
let rawLists = nytOverviewResponses.last?.results?.lists ?? []
// Build a value-typed array to avoid SwiftData faulting during sort
let monthly = rawLists
.filter { $0.updateFrequency == Updated.monthly.rawValue }
.map { (name: $0.displayName, encoded: $0.listNameEncoded, model: $0) }
.sorted { $0.name < $1.name }
return Section(header: Text("Monthly lists to be published on \(nytOverviewResponses.last?.results?.publishedDate ?? "-")")) {
ForEach(monthly, id: \.encoded) { item in
Text(item.name).font(Font.custom("Georgia", size: 17))
}
}
}
}
I am a novice developer, so please be kind. 😬
I am developing a simple macOS app backed with SwiftData and trying to set up iCloud sync so data syncs between two Macs running the app. I have added the iCloud capability, checked the CloudKit box, and selected an iCloud Container. Per suggestion of Paul Hudson, my model properties have either default values or are marked as optional, and the only relationship in my model is marked as optional.
@Model
final class Project {
// Stable identifier used for restoring selected project across launches.
var uuid: UUID?
var name: String = ""
var active: Bool = true
var created: Date = Foundation.Date(timeIntervalSince1970: 0)
var modified: Date = Foundation.Date(timeIntervalSince1970: 0)
// CloudKit requires to-many relationships to be optional in this schema.
@Relationship
var timeEntries: [TimeEntry]?
init(name: String, active: Bool = true, uuid: UUID? = UUID()) {
self.uuid = uuid
self.name = name
self.active = active
self.created = .now
self.modified = .now
self.timeEntries = []
}
@Model
final class TimeEntry {
// Core timing fields.
var start: Date = Foundation.Date(timeIntervalSince1970: 0)
var end: Date = Foundation.Date(timeIntervalSince1970: 0)
var codeRawValue: String?
var activitiesRawValue: String = ""
// Inverse relationship back to the owning project.
@Relationship(inverse: \Project.timeEntries)
var project: Project?
init(
start: Date = .now,
end: Date = .now.addingTimeInterval(60 * 60),
code: BillingCode? = nil,
activities: [ActivityType] = []
) {
self.start = start
self.end = end
self.codeRawValue = code?.rawValue
self.activitiesRawValue = Self.serializeActivities(activities)
}
I have set up the following in the AppDelegate for registering for remote notifications as well as some logging to console that the remote notification token was received and to be notified when when I am receiving remote notifications.
private final class TimeTrackerAppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ notification: Notification) {
print("📡 [Push] Registering for remote notifications")
NSApplication.shared.registerForRemoteNotifications()
}
func application(_ application: NSApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let tokenPreview = deviceToken.map { String(format: "%02x", $0) }.joined().prefix(16)
print("✅ [Push] Registered for remote notifications (token prefix: \(tokenPreview)...)")
}
func application(_ application: NSApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
let nsError = error as NSError
print("❌ [Push] Failed to register for remote notifications: \(nsError.domain) (\(nsError.code)) \(nsError.localizedDescription)")
}
func application(_ application: NSApplication, didReceiveRemoteNotification userInfo: [String: Any]) {
print("📬 [Push] Received remote notification: \(userInfo)")
}
}
In testing, I run the same commit from Xcode on two different Macs logged into the same iCloud account.
My problem is that sync is not reliably working. Starting up the app on both Macs shows that the app successfully registered for remote notifications.
Sometimes, making an edit on Mac 1 is immediately reflected in Mac 2 UI along with didReceiveRemoteNotification message (all occurring while the Mac 2 app remains in foreground). Sometimes, the Mac 2 app needs to be backgrounded and re-foregrounded before the UI shows the updated data.
Sometimes, an edit on Mac 2 will show on Mac 1 only after re-foregrounded but not show any didReceiveRemoteNotification on the Mac 1 console.
Sometimes, an edit on Mac 2 will not show at all on Mac 1 even after re-foregrounding the app.
Sometimes, no edits sync between either Mac.
I had read about how a few years back, there was a bug in macOS where testing iCloud sync between Macs did not work while running from Xcode but would work in TestFlight. For me, running my app in TestFlight on both Macs has never been able to sync any edits between the Macs.
Any idea where I might be going wrong. It seems this should not be this hard and should not be failing so inconsistently. Wondering what I might be doing wrong here.
I have an image field on a Core Data entity with "Allows External Storage" enabled. When I delete a record, the external binary data file remains on disk. How can I ensure that all externally stored data is deleted along with the record?
Hi, I keep trying to use transformable to store an array of strings with SwiftData, and I can see that it is activating the transformer, but it keeps saying that I am still using NSArray instead of NSData.
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unacceptable type of value for attribute: property = "category"; desired type = NSData; given type = Swift.__SwiftDeferredNSArray; value = (
yo,
gurt
).'
terminating due to uncaught exception of type NSException
CoreSimulator 1010.10 - Device: iPhone 16 18.0 (6879535B-3174-4025-AD37-ED06E60291AD) - Runtime: iOS 18.0 (22A3351) - DeviceType: iPhone 16
Message from debugger: killed
@Model
class MyModel: Identifiable, Equatable {
@Attribute(.transformable(by: StringArrayTransformer.self)) var category: [String]?
@Attribute(.transformable(by: StringArrayTransformer.self)) var amenities: [String]?
var image: String?
var parentChunck: HenricoPostDataChunk_V1?
init(category: [String]?, amenities: [String]?) {
self.category = category
self.amenities = amenities
}
}
class StringArrayTransformer: ValueTransformer {
override func transformedValue(_ value: Any?) -> Any? {
print(value)
guard let array = value as? [String] else { return nil }
let data = try? JSONSerialization.data(withJSONObject: array, options: [])
print(data)
return data
}
override func reverseTransformedValue(_ value: Any?) -> Any? {
guard let data = value as? Data else { return nil }
let string = (try? JSONSerialization.jsonObject(with: data, options: [])) as? [String]
print(string)
return string
}
override class func transformedValueClass() -> AnyClass {
return NSData.self
}
override class func allowsReverseTransformation() -> Bool {
return true
}
static func register() {
print("regitsering")
ValueTransformer.setValueTransformer(StringArrayTransformer(), forName: .stringArrayTransformerName)
}
}
extension NSValueTransformerName {
static let stringArrayTransformerName = NSValueTransformerName("StringArrayTransformer")
}
Hello !
I am using this iCloud key value pair mechanism to save small app configuration between iOS and tvOS.
I would say it is working. But when I go back and forth between debug and release (TestFlight) modes, it is like both apps are not connected anymore.
I spend a lot of time restarting all devices, rebuilding, activating / deactivating iCloud capabilities in the Xcode project.
It is like the app is mixing debug and release data.
Is there an easy way to check what is happening exactly ? I know there's nothing on CloudKit console, so ....
Thank you
Frederic
I have a new app I am working on, it uses, a container id like com.me.mycompany.FancyApp.prod, the description in the app is My Fancy App. When I deploy the app via TestFlight on a real device, the sync seems to work, but when I view iCloud->Storage-List, I see my app icon, and the name "prod". Where did the name prod come from? It should be My Fancy App, which is the actual name of the App.
I have been using the basic NSPersistentContainer with 100k+ records for a while now with no issues. The database size can fluctuate a bit but on average it takes up about 22mb on device.
When I switch the container to NSPersistentCloudKitContainer, I see a massive increase in size to ~150mb initially. As the sync engine uploads records to iCloud it has ballooned to over 600mb on device. On top of that, the user's iCloud usage in settings reports that it takes up 1.7gb in the cloud.
I understand new tables are added and history tracking is enabled but the size increase seems a bit drastic. I'm not sure how we got from 22mb to 1.7gb with the exact same data.
A few other things that are important to note:
I import all the 100k+ records at once when testing the different containers. At the time of the initial import there is only 1 relation (an import group record) that all the records are attached to.
I save the background context only once after all the records and the import group have been made and added to the context.
After the initial import, some of these records may have a few new relations added to them over time. I suppose this could be causing some of the size increase, but its only about 20,000 records that are updated.
None of the records include files/ large binary data.
Most of the attributes are encrypted.
I'm syncing to the dev iCloud environment.
When I do make a change to a single attribute in a record, CloudKit reports that every attribute has been modified (not sure if this is normal or not )
Also, When syncing to a new device, the sync can take hours - days. I'm guessing it's having to sync both the new records and the changes, but it exponentially gets slower as more records are downloaded. The console will show syncing activity, but new records are being added at a slower rate as more records are added. After about 50k records, it grinds to a halt and while the console still shows sync activity, only about 100 records are added every hour.
All this to say i'm very confused where these issues are coming from. I'm sure its a combination of how i've setup my code and the vast record count, record history, etc.
If anyone has any ideas it would be much appreciated.
Hello,
the last days I was trying to solve a bug in my Unit Tests related to the CoreData "NSManagedObjectContextObjectsDidChange" Notification.
Im using some kind of Notification handler to save and abstract that for the UI and while the tests are running this notification was triggered with objects that doesn't exists anymore, which has resulted in a crash.
After some debugging I have detected, that the objects in here are really old. The objects here was from few tests ago, where a Merge Conflict happened. In the meantime there was a plenty of resets and deletes of the whole db. I have also seen that the bad notification is the first in the stack trace of the main thread, which is in my opinion also not usual.
So the real question is:
The only difference what I have found for the bad notification to the real notification, was the existence of the key "NSObjectsChangedByMergeChangesKey" in the UserInfo dictionary of the ObjectsDidChange Notification. But this key is nowhere found in the documentation of Apple. Also the search engines does not produce any result. So what is this key and when is this key contained in this notification and when not?
Maybe if I understand this, it helps me to understand the overall issue ...
The app works on a local db but when I try to make it work with iCloud I get errors that I don't understand.
CoreData+CloudKit: -[NSCloudKitMirroringDelegate _performSetupRequest:]_block_invoke(1247): <NSCloudKitMirroringDelegate: 0x10664c200>: Failed to set up CloudKit integration for store: <NSSQLCore: 0x106688140> (URL: file:///var/mobile/Containers/Data/Application/20EF350F-F0FA-4132-97DA-61B60AADB101/Library/Application%20Support/default.store)
<CKError 0x109430e40: "Partial Failure" (2/1011); "Failed to modify some record zones"; uuid = 82ED152A-D015-414D-BB79-AF36E5AF4A8B; container ID = "iCloud.se.Grindegard.MinaRecept"; partial errors: {
com.apple.coredata.cloudkit.zone:defaultOwner = <CKError 0x109431230: "Permission Failure" (10/2007); server message = "Invalid bundle ID for container"; op = E56A3CDA393641F8; uuid = 82ED152A-D015-414D-BB79-AF36E5AF4A8B>
}>
what can be wrong?
Topic:
App & System Services
SubTopic:
iCloud & Data
I'm developing a SwiftUI app using SwiftData and encountering a persistent issue:
Error Message:
Thread 1: Fatal error: Duplicate keys of type 'Bland' 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.
Details:
Occurrence: The error always occurs on the first launch of the app after installation. Specifically, it happens approximately 1 minute after the app starts.
Inconsistent Behavior: Despite no changes to the code or server data, the error occurs inconsistently.
Data Fetching Process:
I fetch data for entities (Bland, CrossZansu, and Trade) from the server using the following process:
Fetch Bland and CrossZansu entities via URLSession.
Insert or update these entities into the SwiftData context.
The fetched data is managed as follows:
func refleshBlandsData() async throws {
if let blandsOnServer = try await DataModel.shared.getBlands() {
await MainActor.run {
blandsOnServer.forEach { blandOnServer in
if let blandOnLocal = blandList.first(where: { $0.code == blandOnServer.code }) {
blandOnLocal.update(serverBland: blandOnServer)
} else {
modelContext.insert(blandOnServer.bland)
}
}
}
}
}
This is a simplified version of my StockListView. The blandList is a @Query property and dynamically retrieves data from SwiftData:
struct StockListView: View {
@Environment(\.modelContext) private var modelContext
@Query(sort: \Bland.sname) var blandList: [Bland]
@Query var users: [User]
@State private var isNotLoaded = true
@State private var isLoading = false
@State private var loadingErrorState = ""
var body: some View {
NavigationStack {
List {
ForEach(blandList, id: \.self) { bland in
NavigationLink(value: bland) {
Text(bland.sname)
}
}
}
.navigationTitle("Stock List")
.onAppear {
doIfFirst()
}
}
}
// This function handles data loading when the app launches for the first time
func doIfFirst() {
if isNotLoaded {
loadDataWithAnimationIfNotLoading()
isNotLoaded = false
}
}
// This function ensures data is loaded with an animation and avoids multiple triggers
func loadDataWithAnimationIfNotLoading() {
if !isLoading {
isLoading = true
Task {
do {
try await loadData()
} catch {
// Capture and store any errors during data loading
loadingErrorState = "Data load failed: \(error.localizedDescription)"
}
isLoading = false
}
}
}
// Fetch data from the server and insert it into the SwiftData model context
func loadData() async throws {
if let blandsOnServer = try await DataModel.shared.getBlands() {
for bland in blandsOnServer {
// Avoid inserting duplicate keys by checking for existing items in blandList
if !blandList.contains(where: { $0.code == bland.code }) {
modelContext.insert(bland.bland)
}
}
}
}
}
Entity Definitions:
Here are the main entities involved:
Bland:
@Model
class Bland: Identifiable {
@Attribute(.unique) var code: String
var sname: String
@Relationship(deleteRule: .cascade, inverse: \CrossZansu.bland)
var zansuList: [CrossZansu]
@Relationship(deleteRule: .cascade, inverse: \Trade.bland)
var trades: [Trade]
}
CrossZansu:
@Model
class CrossZansu: Equatable {
@Attribute(.unique) var id: String
var bland: Bland?
}
Trade:
@Model
class Trade {
@Relationship(deleteRule: .nullify)
var user: User?
var bland: Bland
}
User:
class User {
var id: UUID
@Relationship(deleteRule: .cascade, inverse: \Trade.user)
var trades: [Trade]
}
Observations:
Error Context: The error occurs after the data is fetched and inserted into SwiftData. This suggests an issue with Hashable requirements or duplicate keys being inserted unintentionally.
Concurrency Concerns: The fetch and update operations are performed in asynchronous tasks. Could this cause race conditions?
Questions:
Could this issue be related to how @Relationship and @Attribute(.unique) are managed in SwiftData?
What are potential pitfalls with Equatable implementations (e.g., in CrossZansu) when used in SwiftData entities?
Are there any recommended approaches for debugging "Duplicate keys" errors in SwiftData?
Additional Info:
Error Timing: The error occurs only during the app's first launch and consistently within the first minute.
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?
When my app starts it loads data (of vehicle models, manufacturers, ...) from JSON files into CoreData. This content is static.
Some CoreData entities have fields that can be set by the user, for example an isFavorite boolean field.
How do I tell CloudKit that my CoreData objects are 'static' and must not be duplicated on other devices (that will also load it from JSON files).
In other words, how can I make sure that the CloudKit knows that the record created from JSON for vehicle model XYZ on one device is the same record that was created from JSON on any other device?
I'm using NSPersistentCloudKitContainer.
I’m building an app that edits files in iCloud and uses an NSFilePresenter to monitor changes.
When a conflict occurs, the system calls presentedItemDidGain(_:).
In that method, I merge the versions by reading the current (canonical) version using NSFileVersion.currentVersionOfItem(at:) and the conflicting ones using NSFileVersion.unresolvedConflictVersionsOfItem(at:).
This generally works, but sometimes, if two devices edit the same file at the same time, each device sees its own local version as the current one. For example:
Device A writes fileVerA (slightly later in real time)
Device B writes fileVerB
On Device A all works fine, currentVersionOfItem returns fileVerA, as expected, and unresolvedConflictVersionsOfItem returns [fileVerB].
But on Device B, currentVersionOfItem returns fileVerB!? And unresolvedConflictVersionsOfItem returns the same, local file [fileVerB], without any hint of the other conflicting version, fileVerA.
Later, the newer version from the Device A arrives on Device B as a normal, non-conflicting update via presentedItemDidChange(_:).
This seems to contradict Apple’s documentation:
“The currentVersionOfItemAtURL: method returns an NSFileVersion object representing what’s referred to as the current file; the current file is chosen by iCloud on some basis as the current “conflict winner” and is the same across all devices.”
Is this expected behavior, or a bug in how iCloud reports file versions?
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?