I have implemented CKSyncEngine synchronization, and it works well. I can update data on one device and see the changes propagate to another device quickly. However, the initial sync when a user downloads the app on a new device is a significant issue for both me and my users.
One problem is that the sync engine fetches deletion events from the server. On a new device, the local database is empty, so these deletions are essentially no-ops. This would not be a big problem if there were only a few records or if it was fast. I measured the initial sync and found that there are 150 modified records and 62,168 deletions. Counting these alone takes over five minutes, even without processing them. The deletions do nothing because the local database has nothing to delete, yet they still add a significant delay.
I understand that the sync engine ensures consistency across all devices, but five minutes of waiting with the app open just to insert a small number of records is excessive. The problem would be worse if there were tens of thousands of new records to insert, since downloading and saving the data would take even longer.
This leads to a poor user experience. Users open the app and see data being populated for several minutes, or they are stuck on a screen that says the data is being synchronized with iCloud.
I am wondering if there is a way to make the sync engine ignore deletion events when the state serialization is nil. Alternatively, is there a recommended method for handling initial synchronization more efficiently?
One idea I considered is storing all the data as a backup in iCloud Documents, along with the state serialization at that point in time. When a user opens the app for the first time, I could download the file, extract the data, and set the state serialization to the saved value. I am not sure if this would work. I do not know if state serialization is tied to the device or if it only represents the point where the sync engine left off. My guess is that it might reference some local device storage.
I am not sure what else to try. I could fetch all data using CloudKit, create the sync engine with an empty state serialization, and let it fetch everything again, but that would still take a long time.
My records are very small, mostly a date when something happened and an ID referencing the parent. Since the app tracks watched episodes, I only store the date the user watched the episode and the ID of that episode.
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 run into a strange issue.
If a sheet loads a view that has a SwiftData @Query, and there is an if statement in the view body, I get the following error when running an iOS targetted SwiftUI app under MacOS 26.1:
Set a .modelContext in view's environment to use Query
While the view actually ends up loading the correct data, before it does, it ends up re-creating the sqlite store (opening as /dev/null).
The strange thing is that this only happens if there is an if statement in the body. The statement need not ever evaluate true, but it causes the issue.
Here's an example. It's based on the default xcode new iOS project w/ SwiftData:
struct ContentView: View {
@State private var isShowingSheet = false
var body: some View {
Button(action: { isShowingSheet.toggle() }) {
Text("Show Sheet")
}
.sheet(isPresented: $isShowingSheet, onDismiss: didDismiss) {
VStack {
ContentSheetView()
}
}
}
func didDismiss() { }
}
struct ContentSheetView: View {
@Environment(\.modelContext) private var modelContext
@Query public var items: [Item]
@State var fault: Bool = false
var body: some View {
VStack {
if fault { Text("Fault!") }
Button(action: addItem) {
Label("Add Item", systemImage: "plus")
}
List {
ForEach(items) { item in
Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))
}
}
}
}
private func addItem() {
withAnimation {
let newItem = Item(timestamp: Date())
modelContext.insert(newItem)
}
}
}
It requires some data to be added to trigger, but after adding it and dismissing the sheet, opening up the sheet with trigger the Set a .modelContext in view's environment to use Query. Flipping on -com.apple.CoreData.SQLDebug 1 will show it trying to recreate the database.
If you remove the if fault { Text("Fault!") } line, it goes away. It also doesn't appear to happen on iPhones or in the iPhone simulator.
Explicitly passing modelContext to the ContentSheetView like ContentSheetView().modelContext(modelContext) also seems to fix it.
Is this behavior expected?
I'm experiencing the following error with my SwiftData container when running a build:
Code=134504 "Cannot use staged migration with an unknown model version."
Code Structure - Summary
I am using a versionedSchema to store multiple models in SwiftData. I started experiencing this issue when adding two new models in the newest Schema version. Starting from the current public version, V4.4.6, there are two migrations.
Migration Summary
The first migration is to V4.4.7. This is a lightweight migration removing one attribute from one of the models. This was tested and worked successfully.
The second migration is to V5.0.0. This is a custom migration adding two new models, and instantiating instances of the two new models based on data from instances of the existing models. In the initial testing of this version, no issues were observed.
Issue and Steps to Reproduce
Reproduction of issue: Starting from a fresh build of the publicly released V4.4.6, I run a new build that contains both Schema Versions (V4.4.7 and V5.0.0), and their associated migration stages. This builds successfully, and the container successfully migrates to V5.0.0. Checking the default.store file, all values appear to migrate and instantiate correctly.
The second step in reproduction of the issue is to simply stop running the build, and then rebuild, without any code changes. This fails to initialize the model container every time afterwards. Going back to the simulator after successive builds are stopped in Xcode, the app launches and accesses/modifies the model container as normal.
Supplementary Issue: I have been putting up with the same, persistent issue in the Xcode Preview Canvas of "Failed to Initialize Model Container" This is a 5 in 6 build issue, where builds will work at random. In the case of previews, I have cleared all data associated with all previews multiple times. The only difference being that the simulator is a 100% failure rate after the initial, successful initialization. I assume this is due to the different build structure of previews. Lastly, of note, the Xcode previews fail at the same line in instantiating the model container as the simulator does. From my research into this issue, people say that the Xcode preview is instantiating from elsewhere. I do have a separate model container set up specifically for canvas previews, but the error does not occur in that container, but rather the app's main container.
Possible Contributing Factors & Tested Facts
iOS: While I have experienced issues with SwiftData and the complier in iOS 26, I can rule that out as the issue here. This has been tested on simulators running iOS 18.6, 26.0.1, and 26.1, all encountering failures to initialize model container. While in iOS 18, subsequent builds after the successful migration did work, I did eventually encounter the same error and crash. In iOS 26.0.1 and 26.1, these errors come immediately on the second build.
Container Initialization for V4.4.6
do {
container = try ModelContainer(
for:
Job.self,
JobTask.self,
Day.self,
Charge.self,
Material.self,
Person.self,
TaskCategory.self,
Service.self,
migrationPlan: JobifyMigrationPlan.self
)
} catch {
fatalError("Failed to Initialize Model Container")
}
Versioned Schema Instance for V4.4.6 (V4.4.7 differs only by versionIdentifier)
static var versionIdentifier = Schema.Version(4, 4, 6)
static var models: [any PersistentModel.Type] {
[Job.self, JobTask.self, Day.self, Charge.self, Material.self, Person.self, TaskCategory.self, Service.self]
}
Container Initialization for V5.0.0
do {
let schema = Schema([Jobify.self,
JobTask.self,
Day.self,
Charge.self,
MaterialItem.self,
Person.self,
TaskCategory.self,
Service.self,
ServiceJob.self,
RecurerRule.self])
container = try ModelContainer(
for: schema, migrationPlan: JobifyMigrationPlan.self
)
} catch {
fatalError("Failed to Initialize Model Container")
}
Versioned Schema Instance for V5.0.0
static var versionIdentifier = Schema.Version(5, 0, 0)
static var models: [any PersistentModel.Type] {
[
JobifySchemaV500.Job.self,
JobifySchemaV500.JobTask.self,
JobifySchemaV500.Day.self,
JobifySchemaV500.Charge.self,
JobifySchemaV500.Material.self,
JobifySchemaV500.Person.self,
JobifySchemaV500.TaskCategory.self,
JobifySchemaV500.Service.self,
JobifySchemaV500.ServiceJob.self,
JobifySchemaV500.RecurerRule.self
]
}
Addressing Differences in Object Names
Type-aliasing: All my model types are type-aliased for simplification in view components. All types are aliased as 'JobifySchemeV446.<#Name#>' in V.4.4.6, and 'JobifySchemaV500.<#Name#>' in V5.0.0
Issues with iOS 26: My type-aliases dating back to iOS 17 overlapped with lower level objects in Swift, including 'Job' and 'Material'. These started to be an issue with initializing the model container when running in iOS 26. The type aliases have been renamed since, however the V4.4.6 build with the old names runs and builds perfectly fine in iOS 26
If there is any other code that may be relevant in determining where this error is occurring, I would be happy to add it. My current best theory is simply that I have mistakenly omitted code relevant to the SwiftData Migration.
Hello,
I tried to validate if my app was properly syncing to the cloud. To test this, I created some data in the app, and then deleted the app, and reinstalled. I was expecting the data to still exist but it isn't. Is this a valid test or is the data expected to be deleted when app is deleted?
Topic:
App & System Services
SubTopic:
iCloud & Data
I’m trying to build a CRUD app using SwiftData, @Query model and multidatepicker.
The data from a multidatepicker is stored or persists in SwiftData as Set = [].
My current dilemma is how to use SwiftData and @Query model Predicate to find all records on the current date.
I can’t find any SwiftData documentation or examples @Query using Set = [].
My CRUD app should retrieve all records for the current date. Unfortunately, I don’t know the correct @Query model syntax for Set = [].
Testing Environment: iOS 18.4.1 / macOS 15.4.1
I am working on an iOS project that aims to utilize the user's iCloud Drive documents directory to save a specific directory-based file structure. Essentially, the app would create a root directory where the user chooses in iCloud Drive, then it would populate user generated files in various levels of nested directories.
I have been attempting to use NSMetadataQuery with various predicates and search scopes but haven't been able to get it to directly monitor changes to files or directories that are not in the root directory.
Instead, it only monitors files or directories in the root directory, and any changes in a subdirectory are considered an update to the direct children of the root directory.
Example
iCloud Drive Documents (Not app's ubiquity container)
User Created Root Directory (Being monitored)
File A
Directory A
File B
An insertion or deletion within Directory A would only return a notification with userInfo containing data for NSMetadataQueryUpdateChangedItemsKey relating to Directory A, and not the file or directory itself that was inserted or deleted. (Query results array also only contain the direct children.)
I have tried all combinations of these search scopes and predicates with no luck:
query.searchScopes = [
rootDirectoryURL,
NSMetadataQueryUbiquitousDocumentsScope,
NSMetadataQueryAccessibleUbiquitousExternalDocumentsScope,
]
NSPredicate(value: true)
NSPredicate(format: "%K LIKE '*.md'", NSMetadataItemFSNameKey)
NSPredicate(format: "%K BEGINSWITH %@", NSMetadataItemPathKey, url.path(percentEncoded: false))
I do see these warnings in the console upon starting my query:
[CRIT] UNREACHABLE: failed to get container URL for com.apple.CloudDocs
[ERROR] couldn't fetch remote operation IDs: NSError: Cocoa 257 "The file couldn’t be opened because you don’t have permission to view it."
"Error returned from daemon: Error Domain=com.apple.accounts Code=7 "(null)""
But I am not sure what to make of that, since it does act normally for finding updates in the root directory.
Hopefully this isn't a limitation of the API, as the only alternative I could think of would be to have multiple queries running for each nested directory that I needed updates for.
Topic:
App & System Services
SubTopic:
iCloud & Data
Tags:
Files and Storage
iCloud Drive
Foundation
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?
Hi !
Would anyone know (if possible) how to create backup files to export and then import from the data recorded by SwiftData?
For those who wish, here is a more detailed explanation of my case:
I am developing a small management software with customers and events represented by distinct classes. I would like to have an "Export" button to create a file with all the instances of these 2 classes and another "Import" button to replace all the old data with the new ones from a previously exported file.
I looked for several solutions but I'm a little lost...
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?
If Cloudkit is enabled, SwiftData @Query operation hangs when the View scenePhase becomes active.
Seems like the more @Query calls you have, the more it hangs.
This has been first documented some time ago, but in typical Apple style, it has not been addressed or even commented on.
https://developer.apple.com/forums/thread/761434
Hi everyone,
I’m facing an issue with CloudKit sync getting stuck during initial device migration in my SwiftData-based app.
The app follows a local-first architecture using SwiftData + CloudKit sync, and works correctly for:
✔ Incremental sync
✔ Bi-directional updates
✔ Small datasets
However, when onboarding a new device with large historical data, sync becomes extremely slow or appears stuck. Even after two hours data is not fully synced. ~6900 Transactions
🚨 Problem
When installing the app on a new iPhone and enabling iCloud sync:
• Initial hydration starts
• A small amount of data syncs
• Then sync stalls indefinitely
Observed behaviour:
• iPhone → Mac sync works (new changes sync back)
• Mac → iPhone large historical migration gets stuck
• Reinstalling app / clearing container does not resolve issue
• Sync never completes full migration
This gives the impression that:
CloudKit is trickling data but not progressing after a certain threshold.
The architecture is:
• SwiftData local store
• Manual CloudKit sync layer
• Local-first persistence
• Background push/pull sync
So I understand:
✔ Conflict resolution is custom
✔ Initial import may not be optimized by default
But I expected CloudKit to eventually deliver all records.
Instead, the new device remains permanently in a “partial state”.
⸻
🔍 Observations
• No fatal CloudKit errors
• No rate-limit errors
• No quota issues
• iCloud is available
• Sync state remains “Ready”
• Hydration remains “mostlyReady”
Meaning:
CloudKit does not report failure — but data transfer halts.
⸻
🤔 Questions
Would appreciate guidance on:
Is CloudKit designed to support large initial dataset migration via manual sync layers?
Or is this a known limitation vs NSPersistentCloudKitContainer?
⸻
Does CloudKit internally throttle historical record fetches?
Could it silently stall without error when record volume is high?
⸻
Is there any recommended strategy for:
• Bulk initial migration
• Progressive hydration
• Forcing forward sync progress
⸻
Should initial migration be handled outside CloudKit (e.g. via file transfer / backup restore) before enabling sync?
⸻
🎯 Goal
I want to support:
• Large historical onboarding
• Multi-device sync
• User-visible progress
Without forcing migration to Core Data.
⸻
🙏 Any advice on:
• Best practices
• Debugging approach
• CloudKit behavior in such scenarios
would be greatly appreciated.
Thank you!
Topic:
App & System Services
SubTopic:
iCloud & Data
Tags:
Swift Packages
CloudKit
Swift
Cloud and Local Storage
I'm testing CloudKit Sharing (CKShare) in my app. My app uses CloudKit Sharing to share private data between users (this is not App Store Family Sharing or purchase sharing, it's app-level sharing via CKShare).
To properly test this, I need three or four Apple Accounts with distinct roles in my app. This means I need three/four separate iCloud accounts signed in on test devices. Simulators are probably ok:
two acting as "parents" (share owner and participant):
parent1.sandbox@example.com
parent2.sandbox@example.com,
one or two as a "child" (participant)
child1.sandbox@example.com
child2.sandbox@example.com
except obviously using my domain name.
I attempted to create Sandbox Apple Accounts in App Store Connect, but these don't appear to work with CloudKit Sharing. I then created several standard Apple Accounts, but I've now hit a limit — I believe my mobile number (used for two-factor authentication on the test accounts) has been flagged or rate-limited for account creation, and I can no longer create or verify new accounts with it.
It's also blocked the email addresses associated with those accounts from being used for new account creation.
Can Apple or anyone advise on the recommended approach for testing CloudKit Sharing with multiple participants?
are Sandbox accounts supposed to work for CKShare, or do I need full Apple Accounts?
How do i create and verify these in the correct way to avoid hitting these limits or breaking terms of service?
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 ...
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 tried to set up iCloud sync. Despite fully isolating and resetting my development environment, the app fails with:
NSCocoaErrorDomain Code=134060 (PersistentStoreIncompatibleVersionHashError)
What I’ve done:
Created a brand new CloudKit container
Created a new bundle ID and app target
Renamed the Core Data model file itself
Set a new model version
Used a new .sqlite store path
Created a new .entitlements file with the correct container ID
Verified that the CloudKit dashboard shows no records
Deleted and reinstalled the app on a real device
Also tested with “Automatically manage signing” and without
Despite this, the error persists. I am very inexperienced and am not sure what my next step is to even attempt to fix this. Any guidance is apprecitated.
I'm setting up App Entities for my SwiftData models and I'm not sure about the best way to reference SwiftData model properties in the AppEntity.
I have a SwiftData model with many properties:
@Model
final class Contact {
@Attribute(.unique) var id: UUID = UUID()
var name: String
var phoneNumber: String
var email: String
var website: URL?
var birthday: Date?
var notes: String
// ... many more properties
}
I want to expose these properties on my AppEntity so they're available for system features, such as giving Apple Intelligence more context about on-screen content.
struct ContactEntity: AppEntity {
var id: UUID
@Property(title: "Name")
var name: String
@Property(title: "Phone")
var phoneNumber: String
@Property(title: "Email")
var email: String
// ... all the other properties
}
I couldn't find guidance in the documentation for this specific situation. I've considered two approaches:
Add @Property variables to the AppEntity for each SwiftData model property and copy all values from the SwiftData model to the AppEntity in the AppEntity initializer — but I recall this being discouraged in previous WWDC sessions since it duplicates data and can become stale
Use @ComputedProperty to fetch the model and access the single properties — this seems like an alternative, but fetching the entire model just to access individual properties doesn't feel right
What is the recommended approach when SwiftData is the data source?
Thank you!
Hi everyone,
Complete newbie here. Building an app and trying to use Cloudkit. I've added the CloudKit capability, triple checked the entitlements file for appropriate keys, made sure the code signing entitlements are pointing to the correct entitlements file. I've removed and cleared all of those settings and even created a new container as well as refreshed the signing. I just can't seem to figure out why I keep getting this error:
Significant issue at CKContainer.m:747: In order to use CloudKit, your process must have a com.apple.developer.icloud-services entitlement. The value of this entitlement must be an array that includes the string "CloudKit" or "CloudKit-Anonymous".
Any guidance is greatly appreciated.
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))
}
}
}
}
It takes a few seconds, sometimes a few minutes for records to be downloaded back from CloudKit when the user reinstalls the app, which leads users to thinking their data was lost. I would like to know if there’s any way to provide a visual feedback about the current CloudKit sync status so I can let users know their data is being in fact downloaded back to their devices.
I have used core data before via the model editor. This is the first time I'm using swift data and that too with CloudKit. Can you tell me if the following model classes are correct?
I have an expense which can have only one sub category which in turn belongs to a single category. Here are my classes...
// Expense.swift
// Pocket Expense Diary
//
// Created by Neerav Kothari on 16/05/25.
//
import Foundation
import SwiftData
@Model
class Expense {
@Attribute var expenseDate: Date? = nil
@Attribute var expenseAmount: Double? = nil
@Attribute var expenseCategory: Category? = nil
@Attribute var expenseSubCategory: SubCategory? = nil
var date: Date {
get {
return expenseDate ?? Date()
}
set {
expenseDate = newValue
}
}
var amount: Double{
get {
return expenseAmount ?? 0.0
}
set {
expenseAmount = newValue
}
}
var category: Category{
get {
return expenseCategory ?? Category.init(name: "", icon: "")
}
set {
expenseCategory = newValue
}
}
var subCategory: SubCategory{
get {
return expenseSubCategory ?? SubCategory.init(name: "", icon: "")
}
set {
expenseSubCategory = newValue
}
}
init(date: Date, amount: Double, category: Category, subCategory: SubCategory) {
self.date = date
self.amount = amount
self.category = category
self.subCategory = subCategory
}
}
//
// Category.swift
// Pocket Expense Diary
//
// Created by Neerav Kothari on 16/05/25.
//
import Foundation
import SwiftData
@Model
class Category {
@Attribute var categoryName: String? = nil
@Attribute var categoryIcon: String? = nil
var name: String {
get {
return categoryName ?? ""
}
set {
categoryName = newValue
}
}
var icon: String {
get {
return categoryIcon ?? ""
}
set {
categoryIcon = newValue
}
}
@Relationship(inverse: \Expense.expenseCategory) var expenses: [Expense]? = []
init(name: String, icon: String) {
self.name = name
self.icon = icon
}
}
// SubCategory.swift
// Pocket Expense Diary
//
// Created by Neerav Kothari on 16/05/25.
//
import Foundation
import SwiftData
@Model
class SubCategory {
@Attribute var subCategoryName: String? = nil
@Attribute var subCategoryIcon: String? = nil
var name: String {
get {
return subCategoryName ?? ""
}
set {
subCategoryName = newValue
}
}
var icon: String {
get {
return subCategoryIcon ?? ""
}
set {
subCategoryIcon = newValue
}
}
@Relationship(inverse: \Expense.expenseSubCategory) var expenses: [Expense]? = []
init(name: String, icon: String) {
self.name = name
self.icon = icon
}
}
The reason why I have wrappers is the let the existing code (before CloudKit was integrated), work.
In future versions I plan to query expenses even via category or sub category. I particularly doubt for the relationship i have set. should there be one from category to subcategory as well?