When query, no record returned:
but using fetch, can see the record, while in a strange status: "Record not found"
iCloud & Data
RSS for tagLearn how to integrate your app with iCloud and data frameworks for effective data storage
Post
Replies
Boosts
Views
Activity
I am trying to test CloudKit for sync, and am testing with the Xcode (15.4) SwiftUI templates (CoreData and SwiftData variants) and also with the CKSyncEngine sample-cloudkit-sync-engine example.
I am then testing sync by running app in my MacBook and my iPhone. Generally sync is working, but the behavior is very different when syncing changes from macOS -> iOS compared to from iOS -> macOS:
I open app on by my MacBook and iPhone
I add item on my MacBook, it shows up a second later on iPhone
On the other hand, if I add item on my iPhone it never shows up on my MacBook until I send app to background and then bring back to foreground.
Is this known/expected behavior? Any way to fix?
I assume this is a CKSyncEngine issue since the behavior is the same across all the different app setups and I think they all have CKSyncEngine in common.
For the sample-cloudkit-sync-engine example I have also tried calling try await self.database.syncEngine.fetchChanges(.init(scope: .all)) on the mac, but that doesn't seem to help. I still need to put app into background and then bring back to foreground before it will show changes.
I would expect changes to show up in my Mac UI without having to send app to background.
Target
tvOS 17.4
macOS Version
14.5
Xcode Version
15.4 (15F31d)
I am working on integrating SwiftData (not migrating from CoreData) into an app in active development for tvOS, and I cannot get the project to compile whenever the @Model macro is introduced.
I've traced every error back to the code generated by the @Model, and commenting it out removes the errors. I am able to use @Model on a fresh project, but any attempt to import SwiftData results in the build failing with the following errors:
/var/folders/t5/c9qp7_4j19x9s3p3z26kn6v80000gn/T/swift-generated-sources/@__swiftmacro_9AeolusKit11DeviceModel0D0fMe_.swift:1:1 Type 'DeviceModel' does not conform to protocol 'Observable'
/var/folders/t5/c9qp7_4j19x9s3p3z26kn6v80000gn/T/swift-generated-sources/@__swiftmacro_9AeolusKit11DeviceModelC2id18_PersistedPropertyfMa_.swift:4:9 Member 'setValue' cannot be used on value of type 'any BackingData<DeviceModel>'; consider using a generic constraint instead
/var/folders/t5/c9qp7_4j19x9s3p3z26kn6v80000gn/T/swift-generated-sources/@__swiftmacro_9AeolusKit11DeviceModel0D0fMe_.swift:4:36 'Observable' is not a member type of struct 'AeolusKit.Observation'
/var/folders/t5/c9qp7_4j19x9s3p3z26kn6v80000gn/T/swift-generated-sources/@__swiftmacro_9AeolusKit11DeviceModelC2id18_PersistedPropertyfMa_.swift:4:50 Cannot convert value of type 'String' to expected argument type 'PersistentIdentifier'
/var/folders/t5/c9qp7_4j19x9s3p3z26kn6v80000gn/T/swift-generated-sources/@__swiftmacro_9AeolusKit11DeviceModelC2id18_PersistedPropertyfMa_.swift:8:54 Cannot infer key path type from context; consider explicitly specifying a root type
/var/folders/t5/c9qp7_4j19x9s3p3z26kn6v80000gn/T/swift-generated-sources/@__swiftmacro_9AeolusKit11DeviceModelC2id18_PersistedPropertyfMa_.swift:12:64 Cannot infer key path type from context; consider explicitly specifying a root type
/var/folders/t5/c9qp7_4j19x9s3p3z26kn6v80000gn/T/swift-generated-sources/@__swiftmacro_9AeolusKit11DeviceModel0D0fMm_.swift:25:50 Type 'Observation' has no member 'ObservationRegistrar'
the code in question causing the error:
import Foundation
import SwiftData
@Model
public final class DeviceModel {
@Attribute(.unique) public var id: String
init(id: String) {
self.id = id
}
}
I've already done the following:
clean the project
erase the contents of the derived directory
restart xcode
restart my mac.
I want to emphasize, I do not believe it is my code causing this issue, as commenting out the @Model result's in a perfectly normal build with no warnings or errors
Any help is appreciated
sample code
let modelConfiguration = ModelConfiguration()
// 1. create mom
guard let mom = NSManagedObjectModel.makeManagedObjectModel(for: [Attachment.self]) else {
fatalError("====> makeManagedObjectModel error")
}
// 2. create description with config url and setting
let description = NSPersistentStoreDescription(url: modelConfiguration.url);
description.shouldAddStoreAsynchronously = false;
container = NSPersistentCloudKitContainer(name: "swiftDataCloudTest", managedObjectModel: mom);
container.persistentStoreDescriptions = [description]
// 3. get modelContainer
let modelContainer = try! ModelContainer(for: Attachment.self, configurations: self.modelConfiguration)
this code works fine on MacOS(14.4.1) and previous iOS 17.x.(iOS 17.2 is OK)
but on iOS 17.5, the app crashes with message
A Core Data error occurred." UserInfo={NSLocalizedFailureReason=Unable to find a configuration named 'default' in the specified managed object model
how can I fix these?
I'm attempting to save a CKQuerySubscription in production, in the public database, but I'm seeing the following error:
Failed to create CloudKit subscription for Encounter: <CKError 0x3038f66a0: "Invalid Arguments" (12/2006); server message = "attempting to create a subscription in a production container"; op = 093C69242BCC1B0A; uuid = D6E49665-6B8A-4F16-BBD8-B188A4E71F70; container ID = "iCloud.com...">
This is the query’s predicate: NSPredicate(format: "users CONTAINS %@", user.recordID), and the same subscription works perfectly fine in the development CloudKit environment. I have a queryable index on the users field in both environments. Also, I have saved a TRUEPREDICATE CKQuerySubscription in production, and that works perfectly. Does anyone know what I could be missing here?
Hi, I've been working on an app that - so far - has only had to deal with offline data store.
The usage is fairly simple: the user picks their favourite tv shows and networks, and they get persisted with SwiftData with all the correct relationships.
Now, I would like to migrate the local storage of the users to a private CloudKit db, but every time I upgrade the app, the data seems to disappear completely.
This is the snippet evolved through the attempt of migrating the data:
Current Production code
public static func makeModelContainer() -> ModelContainer {
do {
let processRequiresInMemory = ProcessInfo.processInfo.arguments.contains("inMemoryDatabasePreferred")
let modelConfiguration = ModelConfiguration(
isStoredInMemoryOnly: processRequiresInMemory,
groupContainer: .automatic,
cloudKitDatabase: .none
)
let modelContainer = try ModelContainer(
for: Country.self,
Episode.self,
Movie.self,
Season.self,
Show.self,
Network.self,
NetworkSubscription.self,
migrationPlan: AppModelMigrationPlan.self,
configurations: modelConfiguration
)
return modelContainer
} catch {
fatalError("Could not initialize model container")
}
}
Testing CloudKit enabled
public static func makeModelContainer() -> ModelContainer {
do {
let processRequiresInMemory = ProcessInfo.processInfo.arguments.contains("inMemoryDatabasePreferred")
let modelConfiguration = ModelConfiguration(
"synced",
isStoredInMemoryOnly: processRequiresInMemory,
groupContainer: .automatic,
cloudKitDatabase: .automatic
)
let modelContainer = try ModelContainer(
for: Country.self,
Episode.self,
Movie.self,
Season.self,
Show.self,
Network.self,
NetworkSubscription.self,
migrationPlan: AppModelMigrationPlan.self,
configurations: modelConfiguration
)
return modelContainer
} catch {
fatalError("Could not initialize model container")
}
}
}
The differences, which I don't understand fully because I could not find documentation, are:
ModelContainer(...) -> ModelContainer("synced", ...)
cloudKitDatabase, from none to automatic.
I have the feeling that changing the name of the configuration also changes some reference to the db itself, but if I were not to change the name, the app would have crashed because unable to migrate.
What's the best approach to take here?
Hello, I’m upgrading my app from Core Data to SwiftData. Due to my old setup the Core Data store has an explicitly name like „Something.sqlite“, because it was defined via NSPersistentContainer(name: "Something") before switching to SwiftData.
Now my goal is to migrate the Core Data stack to SwiftData, while moving it to an App Group (for Widget support) as well as enable iCloud sync via CloudKit.
Working Migration without App Group & CloudKit
I’ve managed to get my migration running without migrating it to an App Group and CloudKit support like so:
@main
struct MyAppName: App {
let container: ModelContainer
init() {
// Legacy placement of the Core Data file.
let dataUrl = URL.applicationSupportDirectory.appending(path: "Something.sqlite")
do {
// Create SwiftData container with migration and custom URL pointing to legacy Core Data file
container = try ModelContainer(
for: Foo.self, Bar.self,
migrationPlan: MigrationPlan.self,
configurations: ModelConfiguration(url: dataUrl))
} catch {
fatalError("Failed to initialize model container.")
}
}
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(container)
}
}
How To Migrate to App Group & CloudKit?
I’ve already tried to use the ModelConfiguration with a name, but it seems to only look for a .store file and thus doesn’t copy over the Core Data contents.
let fullSchema = Schema([Foo.self, Bar.self])
let configuration = ModelConfiguration("Something", schema: fullSchema)
Can someone help me how to do this migration or point me into the right direction? I can’t find anything relating this kind of migration …
Hi, when setting up our Core Data stack in our iOS app (manually, with a NSManagedObjectModel/Context & NSPersistentStoreCoordinator) we have reports a rare bug we haven't been able to reproduce.
Occasionally when adding a persistent store we get a NSCocoaErrorDomain 256 error (NSFileReadUnknownError) with NSSQLiteErrorDomain=4618 in the user info. That's SQLITE_IOERR_SHMOPEN , which the SQLite docs describe this way:
I/O error within the xShmMap method on the sqlite3_io_methods object while trying to open a new shared memory segment
It seems to specifically /not/ be a SQLITE_FULL error.
Do you know what type of issue can cause this? Or where/how I can start tracking this down?
For a bit of context, I store binary files of about 50KB in my Core Data. I noticed that enabling the "Allows External Storage" option doesn't seem to make any difference.
Additionally, how does this setting work with CloudKit when using NSPersistentCloudKitContainer?
Does this setting affect how the data is loaded into memory when accessed in Core Data in the app?
Thank you very much!
SwiftData offers a #Unique macro as of iOS 18, see here: https://developer.apple.com/documentation/swiftdata/unique(_:)
I was wondering if that one might work when the DB is backed by CloudKit.
I have a simple model with a unique field.
@Model
class M {
@Attribute(.unique)
var value: String
var date: Date
var answer: Int
init(value: String, date: Date = .now, answer: Int = 0) {
self.value = value
self.date = date
self.answer = answer
}
}
I am creating new objects with
let x = M(value: "x")
modelContext.insert(x)
The value field has a unique constraint, and I am observing these differences in iOS 18 beta (Xcode 16.0 beta) from iOS 17.5 (Xcode 15.4):
Multiple objects with the same value field appear in the list.
If explicit modelContext.save() is called, list is not updated with latest values.
Is this something I need to adjust to, or beta issues?
Full source code: https://github.com/paiv/swiftdata-insert-unique-1
Hi,
I updated my iPad to iOS18 beta 1, and it seems to crash my app immediately, even though it's the App Store release version that's running fine on iOS17. The crash report points to some issue in NSManagedObjectContext performBlockAndWait:
Thread 2 name: Dispatch queue: NSManagedObjectContext 0x303498000: CJCloudKitItemsUploaderQueue
Thread 2 Crashed:
0 libsystem_kernel.dylib 0x1f1930254 __pthread_kill + 8
1 libsystem_pthread.dylib 0x2285fcef8 pthread_kill + 268
2 libsystem_c.dylib 0x1a9a76ad8 abort + 128
3 CJournal 0x105428818 0x104e28000 + 6293528
4 CJournal 0x1054261f4 0x104e28000 + 6283764
5 CoreFoundation 0x1a1c40a3c __handleUncaughtException + 660
6 libobjc.A.dylib 0x19eec8210 _objc_terminate() + 132
7 CJournal 0x1053f5ad0 0x104e28000 + 6085328
8 libc++abi.dylib 0x22852087c std::__terminate(void (*)()) + 16
9 libc++abi.dylib 0x228520820 std::terminate() + 108
10 libdispatch.dylib 0x1a99bd174 _dispatch_client_callout + 40
11 libdispatch.dylib 0x1a99cc7b8 _dispatch_lane_barrier_sync_invoke_and_complete + 56
12 CoreData 0x1a9c94a6c -[NSManagedObjectContext performBlockAndWait:] + 264
13 ContactsJournalDataKit 0x10643fb50 -[CJCloudKitModifyRecordsOperation createUnderlyingCKModifyRecordsOperationWithProcessList:withLimit:] + 408
14 ContactsJournalDataKit 0x10643f544 -[CJCloudKitModifyRecordsOperation main] + 848
15 Foundation 0x1a071e2e0 __NSOPERATION_IS_INVOKING_MAIN__ + 16
16 Foundation 0x1a071c530 -[NSOperation start] + 648
17 Foundation 0x1a07947a0 __NSOPERATIONQUEUE_IS_STARTING_AN_OPERATION__ + 16
18 Foundation 0x1a07943ec __NSOQSchedule_f + 172
19 libdispatch.dylib 0x1a99cc350 _dispatch_block_async_invoke2 + 148
20 libdispatch.dylib 0x1a99bd160 _dispatch_client_callout + 20
21 libdispatch.dylib 0x1a99c0610 _dispatch_continuation_pop + 596
22 libdispatch.dylib 0x1a99bfc40 _dispatch_async_redirect_invoke + 580
23 libdispatch.dylib 0x1a99cedf4 _dispatch_root_queue_drain + 392
24 libdispatch.dylib 0x1a99cf5f8 _dispatch_worker_thread2 + 156
25 libsystem_pthread.dylib 0x2285f9c40 _pthread_wqthread + 228
26 libsystem_pthread.dylib 0x2285f6488 start_wqthread + 8
Can anyone shed some light on this? I haven't rebuilt the app with Xcode 16 yet, just wanted to run the App Store version and see if it's compatible without doing anything.
I have a large model. Not just large in complexity but literally there are gigabytes in the average user db.
I want to enable saving data to this model from app extensions. However, I do not want to duplicate code or model setup.
Is it recommended that I migrate to using a shared group model? How do you migrate existing stores to using shared containers?
Or are there better ways to do it? For example, should I create a brand new store that uses a shared container?
What are best practices?
I've been building an app with CKSyncEngine based off the documentation and sample code on GitHub. So far it's been working great, but I still have a number of questions I couldn't find the answer to I'd like to know before going into production. Here's a list in no particular order:
When sending changes, are you expected to always send the entire record or just the fields that changed? It's not clear there would even be a way to know the fields that changed since when we have to populate the CKRecord from our local record, we only know the id.
Likewise, when we get a record that changed on the server, do we always get a complete record even if only a single field changed?
Related to that, if a record has asset(s), is the complete asset also returned on every server change even if we already have a copy locally and it hasn't been modified?
If a record does have an asset, is the asset guaranteed to be downloaded and available at the asset.fileURL location by the time CKSyncEngine calls the delegate? If not, is there a way to know it's still downloading and when it will be available?
Is there a way to lazy load assets to avoid unnecessary data fetching?
If there is a failure during sync, for example if I fail to save just one record out of many, how do I recover from that? Is there a way to retry?
Related, is there a way to verify we're completely in sync with the server?
Is there any way to resync besides deleting the state serialization data and doing a complete sync again?
Can I use CKSyncEngine from the main app and the app extensions if they share a database and state serialization. For example, when adding an image from the share extension. Any caveats to that?
Sorry for all the questions, but I want to make sure this is as efficient and reliable as possible. I'm going to request a Lab as well, but it's the lab request form isn't working at the moment so I figured I'd post here in case it's easier to answer async.
Thanks!
– Zach
In any SwiftData project with undo enabled, I noticed that repeatedly undoing and redoing a change will cause memory to continuously climb. The larger the change, the more memory is consumed. This is surprising to me.
I confirmed this on iOS and macOS using Xcode 15.4 and 16 beta.
To reproduce, simply add undo/redo functionality to any project and repeatedly undo/redo a change. Memory consumption will climb continuously and will not get released.
In Paul Hudson's SwiftData tutorials, he has an entire section about the numerous tricks required to get SwiftData relationships to work correctly. Does anyone know if SwiftData also requires tricks to get the UndoManager to work correctly?
The following videos from WWDC24 say that we can use cloud storage for our SwiftData stores. Video references below:
What's new in SwiftData
Create a custom data store with SwiftData
When watching the videos it shows examples of how we can read and write to a JSON file as a store, rather than using the built in store that comes with SwiftData.
But there are mentions that we can use cloud storage like a backend i.e. a database hosted on a server. The only thing that I'm struggling to figure out and it would be great if we had code samples for this is how to achieve using cloud storage as a store since looking at the current implementations of:
DataStoreConfiguration
DataStore
The required functions we need to implement look synchronous rather than asynchronous so how would or could we handle fetching asynchronous data from cloud storage. So how would we handle this?
Also it would be great if someone could clarify how or if there is a way to send notifications for changes to your store between different devices similar to CloudKit?
Are there there any plans to provide more documentation & sample code for the questions I've asked above?
Feedback FB13857743
I'm currently using Xcode 16 Beta (16A5171c) and I'm getting a crash whenever I attempt to fetch using my ModelContext in my SwiftUI video using the environment I'm getting a crash specifically on iOS 18 simulators.
I've opened up a feedback FB13831520 but it's worth noting that I can run the code I'll explain in detail below on iOS 17+ simulator and devices just fine.
I'm getting the following crash:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'The specified URI is not a valid Core Data URI: x-coredata:///MyApp/XXXXX-XXXXX-XXXX-XXXX-XXXXXXXXXXXX'
It's almost as if on iOS18 SwiftData is unable to find the file on the simulator to perform CRUD operations.
All I'm doing in my project is simply fetching data using the modelContext.
func contains(_ model: MyModel, in context: ModelContext) -> Bool {
let objId = palette.persistentModelID
let fetchDesc = FetchDescriptor<MyModel>(predicate: #Predicate { $0.persistentModelID == objId })
let itemCount = try? context.fetchCount(fetchDesc)
return itemCount != 0
}
I just saw the new SwiftData updates, including the DataStore API. I’m wondering if, in the case of a shared remote datastore, it is possible to enable updates to the model context from the datastore without the model context explicitly requesting them (e.g., through database listeners).
If I’m not mistaken, when you use CloudKit with SwiftData, this happens, right?
How do I access the SwiftData ModelContainer of my app inside the widget extension?
Following the guide to add a Widget Extension I’ve added the necessary target to my project and enabled App Groups.
I’ve seen that the Backyard Birds example code offers an example how to build this, but it encapsulates the SwiftData handling in a separate app package. Therefore the example simply points to the app package. Though, in my case I don’t host my SwiftData in an external app package, but simply inside the regular app target.
So, my question is how and at which point in code do I need to access the ModelContainer?
I've just tried to update a project that uses SwiftData to Swift 6 using Xcode 16 beta 1, and it's not working due to missing Sendable conformance on a couple of types (MigrationStage and Schema.Version):
struct LocationsMigrationPlan: SchemaMigrationPlan {
static let schemas: [VersionedSchema.Type] = [LocationsVersionedSchema.self]
static let stages: [MigrationStage] = []
}
struct LocationsVersionedSchema: VersionedSchema {
static let models: [any PersistentModel.Type] = [
Location.self
]
static let versionIdentifier = Schema.Version(1, 0, 0)
}
This code results in the following errors:
error: static property 'stages' is not concurrency-safe because non-'Sendable' type '[MigrationStage]' may have shared mutable state
static let stages: [MigrationStage] = []
^
error: static property 'versionIdentifier' is not concurrency-safe because non-'Sendable' type 'Schema.Version' may have shared mutable state
static let versionIdentifier = Schema.Version(1, 0, 0)
^
Am I missing something, or is this a bug in the current seed? I've filed this as FB13862584.