i want to save data like images, text,amd mapviews with swiftui. It is only saved but if you delete the app of buy a new iPhone everything is deleted, how can I make if that the information saved on my app is saved even after I update the app, delete the app, or put the app in another iPhone with SwiftUI? i have watched youtube videos and im still confused,please help.
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
Hi all,
As you know, when using SwiftData Cloudkit, all relationships are required to be optional.
In my app, which is a list app, I have a model class Project that contains an array of Subproject model objects. A Subproject also contains an array of another type of model class and this chain goes on and on.
In this type of pattern, it becomes really taxxing to handle the optionals the correct way, i.e. unwrap them as late as possible and display an error to the user if unable to.
It seems like most developers don't even bother, they just wrap the array in a computed property that returns an empty array if nil.
I'm just wondering what is the recommended way by Apple to handle these optionals. I'm not really familiar with how the CloudKit backend works, but if you have a simple list app that only saves to the users private iCloud, can I just handwave the optionals like so many do? Is it only big data apps that need to worry? Or should we always strive to handle them the correct way? If that's the case, why does it seem like most people skip over them? Be great if an Apple engineer could weigh in.
If I use <FetchRequest.returnsDistinctResults> with unique "identifier" property, and there happened to be multiple NSManagedObjects in Core Data that contains the same "identifier", does the FetchRequest retrieve the latest modified/created object?
Is there a way to define the <FetchRequest.returnsDistinctResults> logic to be based on another property (e.g. "creationDate" / "modifiedDate") and the ascension order?
Topic:
App & System Services
SubTopic:
iCloud & Data
In the CloudKit logs I see logs that suggest users getting QUOTA_EXCEEDED error for RecordDelete operations.
{
"time":"21/07/2025, 7:57:46 UTC"
"database":"PRIVATE"
"zone":"***"
"userId":"***"
"operationId":"***"
"operationGroupName":"2.3.3(185)"
"operationType":"RecordDelete"
"platform":"iPhone"
"clientOS":"iOS;18.5"
"overallStatus":"USER_ERROR"
"error":"QUOTA_EXCEEDED"
"requestId":"***"
"executionTimeMs":"177"
"interfaceType":"NATIVE"
"recordInsertBytes":54352
"recordInsertCount":40
"returnedRecordTypes":"_pcs_data"
}
I'm confused as to what this means? Why would a RecordDelete operation have recordInsertBytes? I'd expect a RecordDelete operation to never fail on quotaExceeded and how would I handle that in the app?
My project is using swiftData and I want to implement iCloud sync in it. Now, my data base doesnt have any optional attributes or relationships and CloudKit wants them to be optional.
So, rather than editing all code with unwrapping code for the optionals, how can I provide a bridge that does so in the last stage of actually saving to the store? Sort of, capture it in a proxy object before writing and after reading from the store.
Is there a neat way that can save a lot of debugging? I have code snippets from chat gpt and they are hard to debug. This is my first project in swiftUI.
Thanks.
Neerav
When a user first downloads my application they are prompted to sign into their apple account via a pop up.
I have not had this pop up previously, I believe the change occurred after iOS18.
I have functions that do a few things:
Retrieves userRecordID
Retrieves a userprofile(via userrecordid) from cloudkit.
HI,
swiftdata is new to me and any help would be appreciated.
In my swiftui app I have a functionality that reinstates the database from an archive.
I first move the three database files (database.store datebase.store-wal and database.store-shm) to a new name (.tmp added for backup incase) and then copy the Archived three files to the same location.
the move creates the following errors:
" BUG IN CLIENT OF libsqlite3.dylib: database integrity compromised by API violation: vnode renamed while in use: /private/var/mobile/Containers/Data/Application/499A6802-02E5-4547-83C4-88389AEA50F5/Library/Application Support/database.store.tmp
invalidated open fd: 4 (0x20)"
I get the same message in console for all three files.
then I reinitialise the model container and get no errors as my code below
....
let schema = Schema([....my different models are here])
let config = ModelConfiguration("database", schema: schema)
do {
// Recreate the container with the same store URL
let container = try ModelContainer(for: schema, configurations: config)
print("ModelContainer reinitialized successfully!")
} catch {
print("Failed to reinitialize ModelContainer: (error)")
}
}
I get the success message but when I leave the view (backup-restore view) to the main view I get:
CoreData: error: (6922) I/O error for database at /var/mobile/Containers/Data/Application/499A6802-02E5-4547-83C4-88389AEA50F5/Library/Application Support/database.store. SQLite error code:6922, 'disk I/O error'
and
error: SQLCore dispatchRequest: exception handling request: <NSSQLFetchRequestContext: 0x302920460> , I/O error for database at /var/mobile/Containers/Data/Application/499A6802-02E5-4547-83C4-88389AEA50F5/Library/Application Support/database.store. SQLite error code:6922, 'disk I/O error' with userInfo of {
NSFilePath = "/var/mobile/Containers/Data/Application/499A6802-02E5-4547-83C4-88389AEA50F5/Library/Application Support/database.store";
NSSQLiteErrorDomain = 6922;
}
error: -executeRequest: encountered exception = I/O error for database at /var/mobile/Containers/Data/Application/499A6802-02E5-4547-83C4-88389AEA50F5/Library/Application Support/database.store. SQLite error code:6922, 'disk I/O error' with userInfo = {
NSFilePath = "/var/mobile/Containers/Data/Application/499A6802-02E5-4547-83C4-88389AEA50F5/Library/Application Support/database.store";
NSSQLiteErrorDomain = 6922;
}
CoreData: error: SQLCore dispatchRequest: exception handling request: <NSSQLFetchRequestContext: 0x302920460> , I/O error for database at /var/mobile/Containers/Data/Application/499A6802-02E5-4547-83C4-88389AEA50F5/Library/Application Support/database.store. SQLite error code:6922, 'disk I/O error' with userInfo of {
NSFilePath = "/var/mobile/Containers/Data/Application/499A6802-02E5-4547-83C4-88389AEA50F5/Library/Application Support/database.store";
NSSQLiteErrorDomain = 6922;
}
Can anyone let me know how I should go about this - reseting the database from old backup files by copying over them.
or if there is a way to stop the database and restart it with the new files in swiftdata
my app is an ios app for phone and ipad
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.
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.
Hey there,
Can we bundle our app with our own version of SQLite with extensions that we want. From what I've seen, we aren't allowed to add extensions to the built in IOS SQLite, so would this be the only way to use extensions. I ask this because I want to use the spell fix extension.
I couldn't find a lot of people talking about adding SQLite extensions.
Thank you!
Topic:
App & System Services
SubTopic:
iCloud & Data
Hi,
I have developed a calendar app with swiftData. I have set it to sync iCloud. When testing it, it seems that everything is fine. But after it's released, today, I uninstalled it and reinstalled it again. And I found that iCloud hasn't sync with local swiftData for six days. I have lost six days agenda and relevant information. I have checked the document, and it's said that there is no method to force to sync with iCloud. How to solve the issue? I think that the users can't forgive that it hasn't synced for six days.
Best Wishes,
Topic:
App & System Services
SubTopic:
iCloud & Data
I have a model with a FamilyActivitySelection, currently i'm using a codable struct to store it with UserDefaults, but would prefer strongly to transition to Swift Data
In my app, I've been using ModelActors in SwiftData, and using actors with a custom executor in Core Data to create concurrency safe services.
I have multiple actor services that relate to different data model components or features, each that have their own internally managed state (DocumentService, ImportService, etc).
The problem I've ran into, is that I need to be able to use multiple of these services within another service, and those services need to share the same context. Swift 6 doesn't allow passing contexts across actors.
The specific problem I have is that I need a master service that makes multiple unrelated changes without saving them to the main context until approved by the user.
I've tried to find a solution in SwiftData and Core Data, but both have the same problem which is contexts are not sendable. Read the comments in the code to see the issue:
/// This actor does multiple things without saving, until committed in SwiftData.
@ModelActor
actor DatabaseHelper {
func commitChange() throws {
try modelContext.save()
}
func makeChanges() async throws {
// Do unrelated expensive tasks on the child context...
// Next, use our item service
let service = ItemService(modelContainer: SwiftDataStack.shared.container)
let id = try await service.expensiveBackgroundTask(saveChanges: false)
// Now that we've used the service, we need to access something the service created.
// However, because the service created its own context and it was never saved, we can't access it.
let itemFromService = context.fetch(id) // fails
// We need to be able to access changes made from the service within this service,
/// so instead I tried to create the service by passing the current service context, however that results in:
// ERROR: Sending 'self.modelContext' risks causing data races
let serviceFromContext = ItemService(context: modelContext)
// Swift Data doesn't let you create child contexts, so the same context must be used in order to change data without saving.
}
}
@ModelActor
actor ItemService {
init(context: ModelContext) {
modelContainer = SwiftDataStack.shared.container
modelExecutor = DefaultSerialModelExecutor(modelContext: context)
}
func expensiveBackgroundTask(saveChanges: Bool = true) async throws -> PersistentIdentifier? {
// Do something expensive...
return nil
}
}
Core Data has the same problem:
/// This actor does multiple things without saving, until committed in Core Data.
actor CoreDataHelper {
let parentContext: NSManagedObjectContext
let context: NSManagedObjectContext
/// In Core Data, I can create a child context from a background context.
/// This lets you modify the context and save it without updating the main context.
init(progress: Progress = Progress()) {
parentContext = CoreDataStack.shared.newBackgroundContext()
let childContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
childContext.parent = parentContext
self.context = childContext
}
/// To commit changes, save the parent context pushing them to the main context.
func commitChange() async throws {
// ERROR: Sending 'self.parentContext' risks causing data races
try await parentContext.perform {
try self.parentContext.save()
}
}
func makeChanges() async throws {
// Do unrelated expensive tasks on the child context...
// As with the Swift Data example, I am unable to create a service that uses the current actors context from here.
// ERROR: Sending 'self.context' risks causing data races
let service = ItemService(context: self.context)
}
}
Am I going about this wrong, or is there a solution to fix these errors?
Some services are very large and have their own internal state. So it would be very difficult to merge all of them into a single service. I also am using Core Data, and SwiftData extensively so I need a solution for both.
I seem to have trapped myself into a corner trying to make everything concurrency save, so any help would be appreciated!
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?
I have an app which uses key-value storage and will not sync data past a certain size -- meaning that device "A" will send the data to the cloud but device "B" will never receive the updated data. Device "B" will receive the NSUbiquitousKeyValueStoreDidChangeExternallyNotification that the KVS changed but the data is empty.
The data in in the KVS is comprised of 4 keys, each containing a value of NSData generated by NSKeyedArchiver. The NSData is comprised of property-list data types (e.g. numbers, strings, dates, etc.)
I've verified that the KVS meets the limits of:
A total of 1 MB per app, with a per-key limit of 1 MB
A per-key value size limit of 1 MB, and a maximum of 1024 keys
A maximum length for key strings is 64 bytes using UTF8 encoding
Also, the app has never received an NSUbiquitousKeyValueStoreQuotaViolationChange notification.
Of the 4 keys, 3 of them contain no more than 30 KB of data each. However, one of the keys can contain as much as 160 KB of data which will not sync to another device. Strangely, if I constrain the data to 100 KB it will work, however, that is not ideal as it is a fraction of the necessary data.
I don't see any errors in the debug log either.
Any suggestions on what to try next to get this working?
We are trying to solve for the following condition with SwiftData + CloudKit:
Lots of data in CloudKit
Perform "app-reset" to clear data & App settings and start fresh.
Reset data models with try modelContext.delete(model:_) myModel.count() confirms local deletion (0 records); but iCloud Console shows expectedly slow process to delete.
Old CloudKit data is returning during the On Boarding process.
Questions:
• Would making a new iCloud Zone for each reset work around this, as the new zone would be empty? We're having trouble finding details about how to do this with SwiftData.
• Would CKSyncEngine have a benefit over the default SwiftData methods?
Open to hearing if anyone has experienced a similar challenge and how you worked around it!
Problem Description:
When a device (Device 2) stays offline for an extended period after a record is deleted from another synced device (Device 1) via CloudKit, is it possible for Device 2 to miss the deletion notification when it reconnects, even when using CKSyncEngine?
This scenario raises questions about whether CKSyncEngine can reliably sync changes if CloudKit archives or purges metadata related to deletions during the offline period.
Steps to Reproduce:
At time t0:
· Device 1 and Device 2 sync successfully via CKSyncEngine (shared record RecordA).
Device 2 goes offline.
On Device 1:
· Delete RecordA; sync completes via CKSyncEngine.
Wait for a duration potentially exceeding CloudKit’s change retention window (if such a window exists).
Bring Device 2 back online.
Observe synchronization:
· Expected Behavior: CKSyncEngine removes RecordA from Device 2.
· Observed Behavior: RecordA remains on Device 2.
Key Questions:
Under these conditions, can Device 2 permanently miss the deletion event due to CloudKit’s internal metadata management?
Is there a documented retention policy for CloudKit’s change history, and how does CKSyncEngine handle scenarios where this history is truncated?
What is the recommended pattern to ensure no events are missed, regardless of offline duration?
Clarifications Needed:
· If CloudKit does discard deletion metadata after a period, is this considered a framework limitation, or should developers implement additional safeguards?
· Does CKSyncEngine log warnings or errors when it detects incomplete sync histories?
Environment:
· CKSyncEngine with SQLite
· CloudKit Private Database
· iOS/macOS latest versions
Thank you for clarifying how CKSyncEngine is designed to handle this edge case!
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 just released an App update the didn't touch ANYTHING to do with Core Data (nothing changed in our Coredata code for at least 8 months). The update uses SDK for iOS 18 and Xcode 16.2 and the app now requires iOS 18 and was a minor bug patch and UI improvements for recent iOS changes.
Since the update we are getting a steady trickle of users on iOS 18, some who allow the App to store data in iCloud (Cloudkit) and others who do not, all reporting that after the update to our recent release ALL their data is gone?!
I had not seen this on ANY device until today when I asked a friend who uses the App if they had the issue and it turned out they did, so I hooked their device up to Xcode and ALL the data in the CoreData database was gone?! They are NOT using iCloud. There were no errors or exceptions on Xcode console but a below code returned NO records at all?!
Chart is custom entity and is defined as:
@interface Chart : NSManagedObject {}
let moc = pc.viewContext
let chartsFetch = NSFetchRequest<NSFetchRequestResult>(entityName:"Charts") // Fetch all Charts
do {
let fetchedCharts = try moc.fetch(chartsFetch) as! [Chart]
for chart in fetchedCharts {
....
}
}
A break point inside the do on fetchedCharts show there are NO objects returned.
This is a serious issue and seems like an iOS 18 thing. I saw some people talking in here about NSFetchRequest issues with iOS 18. I need some guidance here from someone Apple engineer here who knows what the status of these NSFetchrequest bugs are and what possible workarounds are. Becasue this problem will grow for me as more users update to iOS 18.
I have a very simple CoreData model that has 1 entity and 2 attributes.
This code works fine:
.onChange(of: searchText) { _, text in
evnts.nsPredicate = text.isEmpty ? nil :NSPredicate(format: "eventName CONTAINS %@ " , text )
but I'd like to also search with the same text string for my second attribute (which is a Date). I believe an OR is appropriate for two conditions (find either one). See attempted code below:
evnts.nsPredicate = text.isEmpty ? nil : NSPredicate(format: "(eventName CONTAINS %@) OR (dueDate CONTAINS %i) " , text )
This crashes immediately %@ does the same. Is there a way to accomplish this?
How is SwiftUI not an option below?