I was hoping for an update of SwiftData which adopted the use of shared and public CloudKit containers, in the same way it does for the private CloudKit container.
So firstly, a big request to any Apple devs reading, for this to be a thing!
Secondly, what would be a sensible way of adding a shared container in CloudKit to an existing app that is already using SwiftData?
Would it be possible to use the new DataStore method to manage CloudKit syncing with a public or shared container?
CloudKit
RSS for tagStore structured app and user data in iCloud containers that can be shared by all users of your app using CloudKit.
Posts under CloudKit tag
200 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
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, 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?
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?
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?
Recently I started getting emails from AppStoreConnect when I submit new builds The email states:
ITMS-90863: Macs with Apple silicon support issue - The app links with libraries that aren’t present in macOS: /usr/lib/swift/libswiftCloudKit.dylib
I can run this app on apple silicon from TestFlight or directly from Xcode and it runs just fine including all iCloud functions. This app has been using iCloud for several years now.
So my question is: Should I just ignore the email or do I need to change something to bring this app into compliance?
When query, no record returned:
but using fetch, can see the record, while in a strange status: "Record not found"
I am currently working on an app that utilizes SwiftData, and I am planning to integrate CloudKit. My current challenge involves managing a Day object that gets inserted when the date changes to track daily progress. Additionally, I want to prompt users to create a username during the app's onboarding process. I am concerned that this could lead to synchronization issues, such as duplicate entries for the same day or multiple user accounts being created. I assume blocking the app until everything is synced from CloudKit is not a practical solution. Does anyone have any recommendations on how to handle this?
Furthermore, I would like to implement a community feature where users can post content. I noticed that CloudKit offers a public database. Is this database suitable for such a feature, or would I need to develop a separate backend to support it?
I have a native SwiftUI Mac app which is based off my iOS app and includes Core Data with iCloud sync. As per my understanding, when a user makes a change on one of the devices a remote notification is sent to the others. I have a widget which displays information from Core Data and the remote notification makes the widget update its information on the next timeline refresh without the user having to open the app manually.
My question is, if an app is closed on macOS so it's not even running in the Dock, do remote notifications work? This page says "the delegate receives this message when the application is running and a remote notification arrives for it". Does that mean the app won't receive remote CloudKit notifications when closed on macOS?
Hello,
im trying to parse a JSON Request into a Swift Data Model. The specific bug happens with the nutriscore.
It works perfectly fine if I do my request and Decode or Encode the Model directly. But when im trying to add it to the Database the field is empty.
Somehow when im iterating through each product (my model) and console log it, it works. But only if there is one product in my database. sometimes when im adding another product, it somehow deletes(?) all nutriscores and the console log prints "nil" for all products. even for the product it worked before.
This right here is the way I insert into my database which should be perfectly fine. And the printing works also perfectly fine and it always displays the correct nutriscore
func dataScanner(_ dataScanner: DataScannerViewController, didAdd addedItems: [RecognizedItem], allItems: [RecognizedItem]) {
for item in addedItems {
if case let .barcode(barcode) = item {
performAPIRequest(with: barcode.payloadStringValue!) { result in
switch result {
case .success(let product):
...
var descriptor: FetchDescriptor<Product> {
var descriptor = FetchDescriptor<Product>(
predicate: #Predicate { $0.code == product.code }
)
descriptor.fetchLimit = 1
return descriptor
}
var products: [Product] = []
products = try! self.parent.context.fetch(descriptor)
print(product.nutriscore ?? "no nutri"); //WORKS PERFECTLY FINE!!
if let existingProduct = products.first {
existingProduct.amount! += 1
existingProduct.lastScannedAt = Date()
} else {
self.parent.context.insert(product)
}
self.processMeals()
case .failure(let error):
print("Error: \(error)")
}
}
}
}
}
This has to be a SwiftData Bug, or why doesn't it work
Is there any good framework that can ease process of syncing strings, structs, bools across devices using icloud.
Currently app doesn't use any cloud functionality.
Any help will be greatly appreciated.
Done this model:
@Model
public final class Category: Codable {
var nom: String = ""
@Relationship(deleteRule: .cascade, inverse: \Property.category)
var properties: [Property]?
}
How to create #predicate to search text in like…
let predicate = #Predicate<Category> { category in
searchText.isEmpty || category.nom.localizedStandardContains(searchText) ||
category.properties.contains {
$0.nom.localizedStandardContains(searchText)
}
}
without this error:
SQLCore dispatchRequest: exception handling request: <NSSQLCountRequestContext: 0x6000038dc620>, to-many key not allowed here with userInfo of (null)
Hi,
does someone knows about the bug, that the NSPersistentCloudKitContainer doesn't return CKShares at the first time? Is this an intended behavior?
My current fix:
let container: NSPersistentCloudKitContainer = ....
// Fix begin
let managedObject = .... // Object which is in a share
let record = container.record(for: managedObject.objectID)
// Fix end
let shares = (try? container.fetchShares(in: nil)) ?? []
If I execute exactly the same code without the fix that I fetch the record first, then it returns 0 shares. With the fix it is currently 9 shares (the actual count of the shares).
Another fix:
let container: NSPersistentCloudKitContainer = ....
// Fix begin
let _ = try? container.fetchShares(in: nil)
Thread.sleep(forTimeInterval: 0.1)
// Fix end
let shares = (try? container.fetchShares(in: nil)) ?? []
For that fix it also returns at the second time the expected count of shares. But without the delay it returns also at the second time zero shares.
Anyone had the same problem and if so, how do you solve it correctly?
Thanks!
We worked with SwiftData, and once CloudKit was integrated, the synchronization worked well. Even if I rerun the app, it works just as well.
However, when I delete the app and reinstall it, I get a Token Expired error and CloudKit doesn't work properly.
My code is organized like this
public lazy var modelContext: ModelContext = { ModelContext(modelContainer) }()
private lazy var modelContainer: ModelContainer = {
let schema = Schema([
Entity1.self,
Entity2.self,
Entity3.self,
])
let modelConfiguration = ModelConfiguration(
schema: schema,
groupContainer: .identifier("myGroupContainer"),
cloudKitDatabase: .automatic
)
do {
return try ModelContainer(for: schema, configurations: [modelConfiguration])
} catch {
fatalError("Could not create ModelContainer: \(error)")
}
}()
The error content is as follows
error: CoreData+CloudKit: -[PFCloudKitImportRecordsWorkItem fetchOperationFinishedWithError:completion:]_block_invoke(707): <PFCloudKitImporterZoneChangedWorkItem: 0x3022c0000 - <NSCloudKitMirroringImportRequest: 0x3036e7ac0> 1A7E53D4-E95B-423F-8887-66360F6D8865> {
(
"<CKRecordZoneID: 0x301bb1bf0; zoneName=com.apple.coredata.cloudkit.zone, ownerName=__defaultOwner__>"
)
} - Fetch finished with error:
<CKError 0x301bb5650: "Partial Failure" (2/1011); "Couldn't fetch some items when fetching changes"; uuid = 3F346302-C3EE-4F72-820C-988287C92C0A; container ID = "MyContainerID"; partial errors: {
com.apple.coredata.cloudkit.zone:__defaultOwner__ = <CKError 0x301bb1830: "Change Token Expired" (21/2026); server message = "client knowledge differs from server knowledge"; op = 515034AC3ADC4348; uuid = 3F346302-C3EE-4F72-820C-988287C92C0A>
}>
error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _importFinishedWithResult:importer:](1390): <PFCloudKitImporter: 0x3000a1240>: Import failed with error:
<CKError 0x301bb5650: "Partial Failure" (2/1011); "Couldn't fetch some items when fetching changes"; uuid = 3F346302-C3EE-4F72-820C-988287C92C0A; container ID = "MyContainerID"; partial errors: {
com.apple.coredata.cloudkit.zone:__defaultOwner__ = <CKError 0x301bb1830: "Change Token Expired" (21/2026); server message = "client knowledge differs from server knowledge"; op = 515034AC3ADC4348; uuid = 3F346302-C3EE-4F72-820C-988287C92C0A>
}>
Forcing the ModelContainer to be reinitialized fixes the problem,
it's a problem to get this error in the first place,
the error doesn't even go to fatal for me, so I don't even know how to verify that it's happening.
Is there something I'm doing wrong, or do you have any good ideas for solving the same problem?
As of yesterday all queries my app makes to the CloudKit database, and requests via the CloudKit console result in 500 internal errors. We have made no changes to the database or app that could have caused this.
The status page for CloudKit database is green.
Here is a response from the CloudKit console:
{code: 500, message: "internal-error", reason: "Internal error", detailedMessage: undefined, requestUuid: "808955a2-e564-459e-ba9b-1101917ce1a4"}
While Query Record show error:
{
"code": 500,
"message": "internal-error",
"reason": "Internal error",
"requestUuid": "c10d378f-7133-4bea-a40d-d957f80f5de4"
}
Every record type in this container show same error.
But other containers of my apps works will.
I recently converted a Core Data app to use CloudKit. Before the conversion, the sqlite file was around 25MB. After the conversion, the file grew to over one gigabyte. I ran sqlite3_analyzer on the new file and found that a single table, ANSCKRECORDMETADATA, used 95% of the storage, 998MB.
Is this to be expected? I confess that the conversion was a bit bumpy. Maybe I did something to create a monstrosity.
If not expected, should I revert to the old Core Data file, create a new CloudKit container, and repeat the conversion.
My App uses Core Data with Cloudkit when users purchased subscription (and uses only Core Data without subscription). My App should normally appear under 'Settings > [User Name] > iCloud > Apps using iCloud - Show All'; however, some users feedback that they my App cannot access iCloud (a message I displayed in my App when CKContainer.default().accountStatus is NOT available or FileManager.default.ubiquityIdentityToken == nil); and they do not see my App name under 'iCloud > Apps using iCloud - Show All'. From the screenshot that one user provided, only Apps from Apple are displayed under 'Apps using iCloud' and no third-party Apps are shown. Since the user can access to 'iCloud > Apple using iCloud', they have signed in to iCloud successfully. They have also tried to restart my App and restart the phone but the iCloud accessibility issue still remains.
How is it possible that iCloud is accessible only to Apps from Apple but not to third party Apps? What can developer do to resolve iCloud accessibility issue here?
It's 2024, and it still seems like the only sure way to cleanly restart cloud sync on an app using NSPersistentCloudKitContainer is to uninstall and reinstall the app. No need to describe how bad that solution is...
Am I missing something? Is there a better way to safely trigger such a restart of the sync (even if it means losing unsaved data and overwriting with what's in the cloud - which is what a reinstall does anyway)?
I'm trying to integrate the option to the player to save their data in the cloud, I integrate the CloudKit, change some stuff to make it work and build in Xcode to my phone.
But when I try to integrate the CloudSave, 50 unnasigned symbols jump,like this one:
Undefined symbol: _CKContainer_Default
I managed to fix them by updating the recommended settings for Xcode.
But then 4 more errors appear:
Sandbox: il2cpp(12538) deny(1) file-read-data /Users/Username/Test Apple Kit
2022/Build/Il2CppOutputProject/IL2CPP/build/deploy_arm64/il2cpp
So, don't let me build and I've looked everywhere but no one seems to had this same error