iCloud & Data

RSS for tag

Learn how to integrate your app with iCloud and data frameworks for effective data storage

CloudKit Documentation

Post

Replies

Boosts

Views

Activity

caches directory counts towards app storage?
throughout all of Foundation's URL documentation, its called out in multiple places that data stored inside an app sandox's caches directory doesn't count towards data and documents usage in the settings app but in practice, it looks like storing data there does in fact count towards documents & data for the app i'm trying to understand if the docs are wrong, if theres a bug in the settings app, or if this is a mistake on my part
3
0
99
17h
Issues during CloudKit record sharing
I am trying to implement record sharing in my project, but when I try to copy the link on the UICloudSharingController, the sheet closes and the link doesn't get copied. My CloudKitManager function: public func shareTeam(_ team: Team) -> AnyPublisher<CKShare, Error> { Future { [weak self] promise in guard let self = self else { promise(.failure(CloudKitError.unknown)) return } let record = team.toCKRecord() let share = CKShare(rootRecord: record) share[CKShare.SystemFieldKey.title] = "Join \(team.name)" as CKRecordValue share.publicPermission = .readWrite let operation = CKModifyRecordsOperation(recordsToSave: [record, share], recordIDsToDelete: nil) operation.savePolicy = .ifServerRecordUnchanged operation.qualityOfService = .userInitiated operation.modifyRecordsResultBlock = { result in switch result { case .success: promise(.success(share)) case .failure(let error): promise(.failure(error)) } } self.privateDatabase.add(operation) } .eraseToAnyPublisher() } ViewModel function: func shareTeam() { guard let selectedTeam = selectedTeam else { return } CloudKitManager.shared.shareTeam(selectedTeam) .receive(on: DispatchQueue.main) .sink { [weak self] completion in switch completion { case .finished: break case .failure(let error): self?.didError = true self?.error = error } } receiveValue: { share in let sharePresenter = SharePresenter( share: share, container: CloudKitManager.shared.container, teamName: selectedTeam.name, rootRecord: selectedTeam.toCKRecord() ) sharePresenter.presentShareSheet() } .store(in: &cancellables) }
1
0
75
1d
CloudKit Dashboard error "Failed to execute query"
Something has caused my CloudKit queries to fail. On the dashboard I get an error message "Failed to execute query" when I try to "SORT BY" a field. The field is listed under Indexes as "sortable". For a different field, when I enter the field under "FILTER BY", and before I tap "Query", I get "No results". That field is listed under the Indexes as "queryable". It used to work fine. I have described this further, with screenshots at FB16114560
1
0
100
3d
Significant increase in 'Other' CloudKit errors
Looking at my CloudKit Telemetry console I noticed a significant increase in 'Other' errors recently. These errors are impacting user experience and I really don't know how to better understand the issues that may be occurring due to the "other" category. If I query the logs for "other" errors, only 2 results show up for the week. There are 2500+ errors in the telemetry graph (see attached). Is anyone else experiencing this or does anyone have a suggestion on how I can better understand this issue? Thank you!
0
0
127
1w
Core Data `context.performAndWait` in an actor
Hello. I am re-writing our way of storing data into Core Data in our app, so it can be done concurrently. The solution I opted for is to have a singleton actor that takes an API model, and maps it to a Core Data object and saves it. For example, to store an API order model, I have something like this: func store( order apiOrder: APIOrder, currentContext: NSManagedObjectContext? ) -&gt; NSManagedObjectID? { let context = currentContext ?? self.persistentContainer.newBackgroundContext() // … } In the arguments, there is a context you can pass, in case you need to create additional models and relate them to each other. I am not sure this is how you're supposed to do it, but it seemed to work. From what I've understood of Core Data and using multiple contexts, the appropriate way use them is with context.perform or context.performAndWait. However, since my storage helper is an actor, @globalActor actor Storage2 { … }, my storage's methods are actor-isolated. This gives me warnings / errors in Swift 6 when I try to pass the context for to another of my actor's methods. let context = … return context.performAndWait { // … if let apiBooking = apiOrder.booking { self.store(booking: apiBooking, context: context) /* causes warning: Sending 'context' risks causing data races; this is an error in the Swift 6 language mode 'self'-isolated 'context' is captured by a actor-isolated closure. actor-isolated uses in closure may race against later nonisolated uses Access can happen concurrently */ } // … } From what I understand this is because my methods are actor-isolated, but the closure of performAndWait does not execute in a thread safe environment. With all this, what are my options? I've extracted the store(departure:context:) into its own method to avoid duplicated code, but since I can't call it from within performAndWait I am not sure what to do. Can I ditch the performAndWait? Removing that makes the warning "go away", but I don't feel confident enough with Core Data to know the answer. I would love to get any feedback on this, hoping to learn!
0
0
137
1w
Use CoreData alongside SwiftData for the "Sharing" feature in the app.
Hello! 😊 I currently manage an app called MoneyKeeper that uses SwiftData for its data storage framework. Many users have requested a "sharing" feature, but unfortunately, SwiftData does not yet support this functionality, and it’s unclear when it will. 😭 Initially, I considered using CloudKit and CKSyncEngine to implement quick synchronization and sharing. However, due to the complexity of the current data model’s relationships, modeling it with CloudKit’s schema alone seemed overly complicated and likely to introduce bugs. As a result, I’ve decided to implement the sharing feature using CoreData and CloudKit. My plan to avoid conflicts with SwiftData includes: Keeping the local storage locations for SwiftData and CoreData separate. Using entirely separate CloudKit containers for SwiftData and CoreData. I believe these measures will minimize potential issues, but I’m wondering if there’s anything else I should consider. Using both SwiftData (for the personal database) and CoreData (for the shared database) feels like it could lead to significant technical debt in the future, and I anticipate encountering even more challenges during actual implementation. I’d greatly appreciate your valuable insights on this matter. 🙏 The app MoneyKeeper, currently operated using SwiftData. https://apps.apple.com/app/id6514279917
1
0
165
1w
SwiftData + CKSyncEngine
Hi, I'm building a habit tracking app for iOS and macOS. I want to use up to date technologies, so I'm using SwiftUI and SwiftData. I want to store user data locally on device and also sync data between device and iCloud server so that the user could use the app conveniently on multiple devices (iPhone, iPad, Mac). I already tried SwiftData + NSPersistentCloudKitContainer, but I need to control when to sync data, which I can't control with NSPersistentCloudKitContainer. For example, I want to upload data to server right after data is saved locally and download data from server on every app open, on pull-to-refresh etc. I also need to monitor sync progress, so I can update the UI and run code based on the progress. For example, when downloading data from server to device is in progress, show "Loading..." UI, and when downloading finishes, I want to run some app business logic code and update UI. So I'm considering switching from NSPersistentCloudKitContainer to CKSyncEngine, because it seems that with CKSyncEngine I can control when to upload and download data and also monitor the progress. My database schema (image below) has relationships - "1 to many" and "many to many" - so it's convenient to use SwiftData (and underlying CoreData). Development environment: Xcode 16.1, macOS 15.1.1 Run-time configuration: iOS 18.1.1, macOS 15.1.1 My questions: 1-Is it possible to use SwiftData for local data storage and CKSyncEngine to sync this local data storage with iCloud? 2-If yes, is there any example code to implement this? I've been studying the "CloudKit Samples: CKSyncEngine" demo app (https://github.com/apple/sample-cloudkit-sync-engine), but it uses a very primitive approach to local data storage by saving data to a JSON file on disk. It would be very helpful to have the same demo app with SwiftData implementation! 3-Also, to make sure I don't run into problems later - is it okay to fire data upload (sendChanges) and download (fetchChanges) manually with CKSyncEngine and do it often? Are there any limits how often these functions can be called to not get "blocked" by the server? 4-If it's not possible to use SwiftData for local data storage and CKSyncEngine to sync this local data storage with iCloud, then what to use for local storage instead of SwiftData to sync it with iCloud using CKSyncEngine? Maybe use SwiftData with the new DataStore protocol instead of the underlying CoreData? All information highly appreciated! Thanks, Martin
3
0
228
1w
Ongoing Issues with ModelActor in SwiftData?
After the problems with the ModelActor in iOS 18, it seemed like the ModelActor became more stable with iOS 18.1 and macOS 15.1. However, I’m still encountering many problems and crashes. I wanted to ask if these issues are related to my persistence layer architecture or if they’re still inherent to the ModelActor itself. I’ve generally followed the blog posts: https://fatbobman.com/en/posts/practical-swiftdata-building-swiftui-applications-with-modern-approaches/ and https://brightdigit.com/tutorials/swiftdata-modelactor/ and aim to achieve the following: I have a single DataProvider that holds the ModelContainer and uses it to configure and initialize a single DataHandler. These are created once at app launch and injected into the SwiftUI view hierarchy as EnvironmentObjects. Since I need to access the SwiftData models not only in SwiftUI but also indirectly in ViewModels or UIKit views, all read operations on the models should go through the DataProvider ( ModelContainrs MainContext), while all other CRUD operations are handled centrally via the single DataHandler (executed within a single ModelActor). Additionally, I want to monitor the entire container using another ModelActor, initialized in the DataProvider, which tracks changes to objects using TransactionHistory. I’ve managed to implement this to some extent, but I’m facing two main issues: ModelActor and Main Actor Requirement The ModelActor only updates SwiftUI views when initialized via the main context of the ModelContainer and therefore runs on the Main Actor. It would be ideal for this to work in the background, but the issue with the ModelActor that existed previously doesn’t seem to have been resolved in iOS 18.1/macOS 15.1—am I wrong about this? Frequent Crashes (more severe) Crashes occur, especially when multiple windows on macOS or iPadOS access the same DataHandler to update models. This often leads to crashes during read operations on models by a SwiftUI view, with logs like: Object 0x111f15480 of class _ContiguousArrayStorage deallocated with non-zero retain count 3. This object's deinit, or something called from it, may have created a strong reference to self which outlived deinit, resulting in a dangling reference. error: the replacement path doesn't exist: "/var/folders/gs/8rwdjczj225d1pj046w3d97c0000gn/T/swift-generated-sources/@__swiftmacro_12SwiftDataTSI3TagC4uuID18_PersistedPropertyfMa_.swift" Can't show file for stack frame : <DBGLLDBStackFrame: 0x34d28e170> - stackNumber:1 - name:Tag.uuID.getter. The file path does not exist on the file system: /var/folders/gs/8rwdjczj225d1pj046w3d97c0000gn/T/swift-generated-sources/@__swiftmacro_12SwiftDataTSI3TagC4uuID18_PersistedPropertyfMa_.swift This error usually happens when there are multiple concurrent accesses to the DataHandler/ModelActor. However, crashes also occur sporadically during frequent accesses from a single view with an error like "the replacement path doesn't exist." It also seems like having multiple ModelActors, as in this case (one for observation and one for data changes), causes interference and instability. The app appears to crash less frequently when the observer is not initialized, but I can’t verify this—it might just be a coincidence. My Question: Am I fundamentally doing something wrong with the ModelActors or the architecture of my persistence layer?
3
0
264
1w
Ongoing Issues with ModelActor in SwiftData?
After the significant issues with the ModelActor in iOS 18, it seemed like the ModelActor became more stable with iOS 18.1 and macOS 15.1. However, I’m still encountering problems and crashes. I wanted to ask if these issues are related to my persistence layer architecture or if they’re still inherent to the ModelActor itself. I’ve generally followed the blog posts: https://fatbobman.com/en/posts/practical-swiftdata-building-swiftui-applications-with-modern-approaches/ and https://brightdigit.com/tutorials/swiftdata-modelactor/ and aim to achieve the following: I have a single DataProvider that holds the ModelContainer and uses it to configure and initialize a single DataHandler. These are created once at app launch and injected into the SwiftUI view hierarchy as EnvironmentObjects. Since I need to access the SwiftData models not only in SwiftUI but also indirectly in ViewModels or UIKit views, all read operations on the models should go through the DataProvider (and its MainContext), while all other CRUD operations are handled centrally via the single DataHandler (executed within a single ModelActor). Additionally, I want to monitor the entire container using another ModelActor, initialized in the DataProvider, which tracks changes to objects using TransactionHistory. I’ve managed to implement this to some extent, but I’m facing two main issues: 1. ModelActor and Main Actor Requirement The ModelActor only updates SwiftUI views when initialized via the maincontext of the ModelContainer and therefore runs on the Main Actor. It would be ideal for this to work in the background, but the issue with the ModelActor that existed previously doesn’t seem to have been resolved in iOS 18.1/macOS 15.1—am I wrong about this? 2. Frequent Crashes (more severe) Crashes occur, especially when multiple windows on macOS or on iPad access the same DataHandler to update models. This often leads to crashes during read operations on models by a SwiftUI view (but not only), with logs like: error: the replacement path doesn't exist: "/var/folders/gs/8rwdjczj225d1pj046w3d97c0000gn/T/swift-generated-sources/@__swiftmacro_12SwiftDataTSI3TagC4uuID18_PersistedPropertyfMa_.swift" Can't show file for stack frame : <DBGLLDBStackFrame: 0x34d28e170> - stackNumber:1 - name:Tag.uuID.getter. The file path does not exist on the file system: /var/folders/gs/8rwdjczj225d1pj046w3d97c0000gn/T/swift-generated-sources/@__swiftmacro_12SwiftDataTSI3TagC4uuID18_PersistedPropertyfMa_.swift This error usually happens when there are multiple concurrent accesses to the DataHandler/ModelActor. However, crashes also occur sporadically during frequent accesses from a single view with an error like "the replacement path doesn't exist." It also seems like having multiple ModelActors, as in this case (one for observation and one for data changes), causes interference and instability. The app appears to crash less frequently when the observer is not initialized, but I can’t verify this—it might just be a coincidence. My Question: Am I fundamentally doing something wrong with the ModelActors or the architecture of my persistence layer?
1
0
161
1w
Correct way to remove arrays containing model objects in SwiftData
Are there any differences (either performance or memory considerations) between removing an array of model objects directly using .removeAll() vs using modelContext? Or, are they identical? Attached below is an example to better illustrate the question (i.e., First Way vs Second Way) // Model Definition @Model class GroupOfPeople { let groupName: String @Relationship(deleteRule: .cascade, inverse: \Person.group) var people: [Person] = [] init() { ... } } @Model class Person { let name: String var group: GroupOfPeople? init() { ... } } // First way struct DemoView: View { @Query private groups: [GroupOfPeople] var body: some View { List(groups) { group in DetailView(group: group) } } } struct DetailView: View { let group: GroupOfPeople var body: some View { Button("Delete All Participants") { group.people.removeAll() } } // Second way struct DemoView: View { @Query private groups: [GroupOfPeople] var body: some View { List(groups) { group in DetailView(group: group) } } } struct DetailView: View { @Environment(\.modelContext) private var context let group: GroupOfPeople var body: some View { Button("Delete All Participants") { context.delete(model: Person.self, where: #Predicate { $0.group.name == group.name }) } // assuming group names are unique. more of making a point using modelContext instead }
0
0
140
2w
SwiftData Quakes Sample app decoding errors from null magnitudes
Hi! I believe there might be a small bug in the SwiftData Quakes Sample App.^1 The Quakes app requests a JSON feed from USGS.^2 What seems to be breaking is that apparently earthquake entities from USGS can return with null magnitudes. That is throwing errors from the decoder: struct GeoFeatureCollection: Decodable { let features: [Feature] struct Feature: Decodable { let properties: Properties let geometry: Geometry struct Properties: Decodable { let mag: Double let place: String let time: Date let code: String } struct Geometry: Decodable { let coordinates: [Double] } } } which is expecting mag to not be nil. Here is my workaround: struct GeoFeatureCollection: Decodable { let features: [Feature] struct Feature: Decodable { let properties: Properties let geometry: Geometry struct Properties: Decodable { let mag: Double? let place: String let time: Date let code: String } struct Geometry: Decodable { let coordinates: [Double] } } } And then: extension Quake { /// Creates a new quake instance from a decoded feature. convenience init(from feature: GeoFeatureCollection.Feature) { self.init( code: feature.properties.code, magnitude: feature.properties.mag ?? 0.0, time: feature.properties.time, name: feature.properties.place, longitude: feature.geometry.coordinates[0], latitude: feature.geometry.coordinates[1] ) } }
1
0
195
2w
SwiftData Crash: Incorrect actor executor assumption.
I have this actor actor ConcurrentDatabase: ModelActor { nonisolated let modelExecutor: any ModelExecutor nonisolated let modelContainer: ModelContainer init(modelContainer: ModelContainer) { self.modelExecutor = DefaultSerialModelExecutor(modelContext: ModelContext(modelContainer)) self.modelContainer = modelContainer } /// Save pending changes in the model context. private func save() { if self.modelContext.hasChanges { do { try self.modelContext.save() } catch { ... } } } } I am getting a runtime crash on: try self.modelContext.save() when trying to insert something into the database and save Thread 1: Fatal error: Incorrect actor executor assumption; Expected same executor as MainActor. Can anyone explain why this is happening?
2
0
206
2w
Undo in SwiftData deletes all data at once.
When the following models in SwiftData, @Model final class UndoRedoData { var id: [Int] init(id: [Int]) { self.id = id } } I created the following code. struct ContentView: View { @ObservedObject var swiftDataViewModel = SwiftDataArrayViewModel.shared @State private var idArray: [Int] = [1,2,3,4] @State private var firstviewSwich: Bool = true @State private var twoviewSwich: Bool = false @State private var threeviewSwich: Bool = false var body: some View { VStack { if firstviewSwich == true { Button(action: addItem) { Text("1.New Item") } } if twoviewSwich == true { Button { forArrayData() } label: { Text("2.Data Road") } } if threeviewSwich == true { Button(action: undoItem) { Text("3.Undo") } } } } private func addItem() { withAnimation { let newItem = UndoRedoData(id: [1,2,3,4]) swiftDataViewModel.taskContext.insert(newItem) do { try swiftDataViewModel.taskContext.save() } catch { print(error) } swiftDataViewModel.fetchItems() firstviewSwich.toggle() twoviewSwich.toggle() } } private func forArrayData() { twoviewSwich.toggle() for data in idArray { swiftDataViewModel.idUndoCreate(id: data, undoManager: swiftDataViewModel.arrayItemUndoManager) } threeviewSwich.toggle() } private func undoItem() { swiftDataViewModel.arrayItemUndoManager.undo() threeviewSwich.toggle() firstviewSwich.toggle() } } class SwiftDataArrayViewModel: ObservableObject { static let shared = SwiftDataArrayViewModel() let modelContainer: ModelContainer @ObservationIgnored lazy var taskContext: ModelContext = { return ModelContext(modelContainer) }() @Published var arrayItems = [UndoRedoData]() @Published var arrayItemUndoManager = UndoManager() init() { let schema = Schema([UndoRedoData.self]) let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false) do { modelContainer = try ModelContainer(for: schema, configurations: [modelConfiguration]) } catch { fatalError(error) } fetchItems() } func fetchItems() { let fetchDescriptor = FetchDescriptor<UndoRedoData>() do { arrayItems = try taskContext.fetch(fetchDescriptor) } catch { fatalError(error) } } func idUndoCreate(id: Int, undoManager: UndoManager?) { undoManager?.registerUndo(withTarget: self) { target in target.removeID() } } func removeID() { if let firstUndoRedoData = arrayItems.first { print("Before Delete:\(firstUndoRedoData.id)") if !firstUndoRedoData.id.isEmpty { firstUndoRedoData.id.removeLast() } print("After Delete:\(firstUndoRedoData.id)") } do { try taskContext.save() } catch { print(error) } fetchItems() } } In this code, 1. Create an Item in New Item, 2. Execute Data Road and register the data in the array that is the same value as the data created in New Item in SwiftData one by one in UndoManager by for data in idArray. This is done because the data in the array and the data created by New Item in SwiftData can be known in advance. private func forArrayData() { twoviewSwich.toggle() for data in idArray { swiftDataViewModel.idUndoCreate(id: data, undoManager: swiftDataViewModel.arrayItemUndoManager) } // class SwiftDataArrayViewModel: ObservableObject func idUndoCreate(id: Int, undoManager: UndoManager?) { undoManager?.registerUndo(withTarget: self) { target in target.removeID() } } After registering in UndoManager, when Undo is executed with 3. Undo, instead of being able to perform Undo where one id is deleted each time, all the data of the id in SwiftData is deleted in a one-time Undo. I would like to be able to delete one id each time Undo is performed and restore them in sequence, but I can only delete them all once. Does this mean that such registration to UndoManager should not be done with for statements, etc.? Or is there another problem in the code? I want to make sure that one id is deleted for each Undo executed.
1
0
190
2w
Core Data and Background Tasks
Hello, our application works with Core Data to save some datas about its activity. We have background Tasks implemented and our app execution in background shows this error message in the Logs: error: Failed to acquire background task assertion for task 'CoreData: Executing write request'. Anyone could explain what this message means? Could it be that NSManagedObjectContext changes might not be written?
1
0
172
2w