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

Core Data transformable vs relationship
I'm working on an app that is using Core Data. I have a custom big number class that boils down to a double and an integer, plus math functions. I've been using transformable types to store these big numbers, but its forcing me to do a lot of ugly casts since the number class is used throughout the application. I figure I can either have my stored values be named differently (e.g. prefix with underscore) and have a computed variable to cast it to the correct type, or find some way to move the big number class to being an NSManagedObject. The issue with this is that the inverse relationships would be massive for the big number class, since multiple entities use the class in multiple properties already. Would it be recommended that I just keep using Transformable types and casts to handle this, or is there some standard way to handle a case like this in Core Data relationships?
0
0
187
Oct ’24
Backup and Restore a Flutter SQLite database file to iCloud
I'm managing the database with SQLite in Flutter. I want to enable iCloud backup and restore on the Swift side when called from Flutter. I am using the following source code, but it is not working. What could be the cause? Could you provide a method and countermeasure? private func saveFileToICloud(fileName: String, localDatabasePath: String, result: @escaping FlutterResult) { guard let containerName = Bundle.main.object(forInfoDictionaryKey: "ICLOUD_CONTAINER_NAME") as? String else { result(FlutterError(code: "NO_ICLOUD_CONTAINER", message: "iCloud container is not available", details: nil)) return } guard let containerURL = FileManager.default.url(forUbiquityContainerIdentifier: containerName) else { result(FlutterError(code: "NO_ICLOUD_CONTAINER", message: "iCloud container is not available", details: nil)) return } let fileURL = containerURL.appendingPathComponent(fileName) let sourceURL = URL(fileURLWithPath: localDatabasePath) do { if FileManager.default.fileExists(atPath: fileURL.path) { try FileManager.default.removeItem(at: fileURL) } try FileManager.default.copyItem(at: sourceURL, to: fileURL) result("File saved successfully to iCloud: \(fileURL.path)") } catch { result(FlutterError(code: "WRITE_ERROR", message: "Failed to write file to iCloud", details: error.localizedDescription)) } } private func readFileFromICloud(fileName: String, localDatabasePath: String, result: @escaping FlutterResult) { let containerName = ProcessInfo.processInfo.environment["ICLOUD_CONTAINER_NAME"] guard let containerURL = FileManager.default.url(forUbiquityContainerIdentifier: containerName) else { result(FlutterError(code: "NO_ICLOUD_CONTAINER", message: "iCloud container is not available", details: nil)) return } let fileURL = containerURL.appendingPathComponent(fileName) let sourceURL = URL(fileURLWithPath: localDatabasePath) do { if FileManager.default.fileExists(atPath: sourceURL.path) { try FileManager.default.removeItem(at: sourceURL) } try FileManager.default.copyItem(at: fileURL, to: sourceURL) result("File restored successfully to sqlite: \(sourceURL.path)") } catch { result(FlutterError(code: "READ_ERROR", message: "Failed to read file from iCloud", details: error.localizedDescription)) } }
0
0
210
Oct ’24
SwiftData: Predicate using optional Codable enum
Hello, I'm currently developing an app using SwiftData. I want the app to use CloudKit to sync data, so I made sure all my model properties are optional. I've defined a Codable enum as follows: enum Size: Int, Codable { case small case medium case large } I've defined a Drink SwiftData model as follows: @Model class Drink { var name: String? var size: Size? init( name: String? = nil, size: Size? = nil ) { self.name = name self.size = size } } In one of my Views, I want to use a @Query to fetch the data, and use a Predicate to filter the data. The Predicate uses the size enumeration of the Drink model. Here is the code: struct DrinksView: View { @Query var drinks: [Drink] init() { let smallRawValue: Int = Size.small.rawValue let filter: Predicate<Drink> = #Predicate<Drink> { drink in if let size: Size = drink.size { return size.rawValue == smallRawValue } else { return false } } _drinks = Query(filter: filter) } var body: some View { List { ForEach(drinks) { drink in Text(drink.name ?? "Unknown Drink") } } } } The code compiles, but when I run the app, it crashes with the following error: Thread 1: Fatal error: Couldn't find \Drink.size!.rawValue on Drink with fields [SwiftData.Schema.PropertyMetadata(name: "name", keypath: \Drink.name, defaultValue: nil, metadata: nil), SwiftData.Schema.PropertyMetadata(name: "size", keypath: \Drink.size, defaultValue: nil, metadata: nil)] How can I filter my data using this optional variable on the Drink model? Thanks, Axel
0
1
268
Oct ’24
After upgrading to XCode 16 app stopped working
Building an app, which worked fine until I updated to XCode 16. The app parses data and saves it to SwiftData, and later that store is used for filtering in data. If I create the store on iOS 18, the store created has issues with relationships, so filtering is not working (I hope that will be fixed in iOS 18.1), so I need to create the store on iOS 17.5. But before saving the parsed objects to the SwiftData (store), I do the checking for dupes. And after Xcode 16 update that is not working anymore on iOS 17.5, (but this part is working fine under iOS 18): Here is my object: import Foundation import SwiftData @Model class CaliberData: Identifiable { var id: UUID = UUID() var sizeHeights: [SizeObject] var featuresABCDIds: [Int] init( id: UUID, sizeHeights: [SizeObject], featuresABCDIds: [Int], ) { self.id = id self.sizeHeights = sizeHeights self.featuresABCDIds = featuresABCDIds } extension CaliberData: Equatable { static func == (lhs: CaliberData, rhs: CaliberData) -> Bool { lhs.featuresABCDIds == rhs.featuresABCDIds && lhs.sizeHeights == rhs.sizeHeights } } SizeObject if needed: @Model class SizeObject: Identifiable, Equatable { @Attribute(.unique) var id: Float @Relationship(inverse: \CaliberData.sizeHeights) private(set) var caliberDataSizesX: [CaliberData]? init(_ size: Float) { self.id = size } } When I am doing the caliberData1 == CaliberData2 comparison to remove dupes before inserting to the SwifData modelContext I am getting exception, and Xcode shows it inside getter part of this expanded section under sizeHeights definition: @storageRestrictions(accesses: _$backingData, initializes: _sizeHeights) init(initialValue) { _$backingData.setValue(forKey: \.sizeHeights, to: initialValue) _sizeHeights = _SwiftDataNoType() } get { _$observationRegistrar.access(self, keyPath: \.sizeHeights) return self.getValue(forKey: \.sizeHeights) } set { _$observationRegistrar.withMutation(of: self, keyPath: \.sizeHeights) { self.setValue(forKey: \.sizeHeights, to: newValue) } } } Following is the stacktrace: #1 0x00000001cc168928 in ___lldb_unnamed_symbol4385 () #2 0x00000001cc163f34 in ___lldb_unnamed_symbol4354 () #3 0x00000001cc165fc4 in ___lldb_unnamed_symbol4369 () #4 0x00000001cc169dd4 in ___lldb_unnamed_symbol4403 () #5 0x00000001cc123854 in SwiftData.PersistentModel.getValue<τ_0_0, τ_0_1 where τ_1_0: SwiftData.RelationshipCollection, τ_1_1 == τ_1_0.PersistentElement>(forKey: Swift.KeyPath<τ_0_0, τ_1_0>) -> τ_1_0 () #6 0x0000000105eda3b0 in CaliberData.sizeHeights.getter at /var/folders/5y/vv3v98ms7jj3z4kj0f3d6f9h0000gq/T/swift-generated-sources/@__swiftmacro_11CaliberDataC11sizeHeights18_PersistedPropertyfMa_.swift:9 #7 0x0000000105ef1a84 in static CaliberData.== infix(_:_:) at ... My assumption is that "it" thinks that object is already inside the modelContext, when it's actually not yet inserted there and should act like regular class (by regular, I mean - like not marked with @Model macro). How can I do objects comparison on iOS 17.5 with Xcode 16 (before they are inserted in modelContext)? Any other options?
3
0
258
Oct ’24
Opening file from iCloud Desktop versus Mail attachment
Am developing an iOS App, which uses a ZipFoundation wrapper around Compression. In XCode, have exported a document type with extension '.MU' in the Info.plist. On iPhone, when attempting to open archive called: 'Snapshot-test.mu' can OPEN as a mobile email attachment but FAILED via Files App referring to "iCloud Drive/Desktop" Here are the respective URLS "file:///private/var/mobile/Containers/Data/Application/&lt;UniqueID&gt;/Documents/Inbox/Snapshot-test.mu" "file:///private/var/mobile/Library/Mobile%20Documents/com~apple~CloudDocs/Desktop/Snapshot-test1.mu" Two questions: Is it possible to grant access to files residing remotely in iCloud? Is "iCloud Drive/Desktop" unique, whereas other iCloud locations would be OK?
0
0
230
Oct ’24
iCloud Documents + UIDocumentBrowserViewController
Our app is a document-based app that uses UIDocumentBrowserViewController. We are facing an issue when the user is creating a new document on iOS/iPadOS when in the “Recents” tab (as opposed to the “Browse” tab). Specifically, the document is saved to a hidden ubiquity container. As a result, the user cannot find the file in the document browser. It also does not appear in “Recents”. The expected behaviour would be a folder with our app's icon on it on the user’s iCloud Drive, which contains the files the user creates when in the “Recents” tab. This issue started to happen when we introduced a new feature that uses iCloud Documents with its own ubiquity container. I'm not sure how UIDocumentBrowserViewController handled saving documents to a default location on iCloud Drive before we had the iCloud Documents entitlement enabled. All I know is that there were no issues. How to recreate the issue: Create a document-based app with UIDocumentBrowserViewController. Run the app and create a document while in the recents tab with iCloud enabled. The document will be stored to a folder on iCloud. Now, enable iCloud Documents and specify a ubiquity container. Then, try to create documents in the Recents tab. The location in which the documents are created cannot be navigated to.
5
0
354
Oct ’24
SwiftData crash on fetch
I have a strange crash which I have problems understanding. It only happens on a few devices, after a ModelContainer migration, and it doesn't seem to crash on the migration itself. The fetch is done in onAppear, and shouldn't necessarily result in a crash, as it is an optional try: let request = FetchDescriptor<Rifle>() let data = try? modelContext.fetch(request) if let data, !data.isEmpty { rifle = data.first(where: { $0.uuid.uuidString == settings.selectedRifleId }) ?? data.first! } When I get logs from users, there seems to be an error in encoding? Exception Type: EXC_BREAKPOINT (SIGTRAP) Exception Codes: 0x0000000000000001, 0x000000018e8bfd78 Termination Reason: SIGNAL 5 Trace/BPT trap: 5 Terminating Process: exc handler [71687] Triggered by Thread: 0 Thread 0 name: Dispatch queue: com.apple.main-thread Thread 0 Crashed: 0 libswiftCore.dylib 0x18e8bfd78 _assertionFailure(_:_:file:line:flags:) + 264 1 SwiftData 0x24e18b480 0x24e14c000 + 259200 2 SwiftData 0x24e193968 0x24e14c000 + 293224 3 SwiftData 0x24e195a78 0x24e14c000 + 301688 4 libswiftCore.dylib 0x18e8e4084 _KeyedEncodingContainerBox.encodeNil<A>(forKey:) + 352 5 libswiftCore.dylib 0x18e8d79f0 KeyedEncodingContainer.encodeNil(forKey:) + 64 6 SwiftData 0x24e19f09c 0x24e14c000 + 340124 7 SwiftData 0x24e1a3dec 0x24e14c000 + 359916 8 libswiftCore.dylib 0x18ec10be8 dispatch thunk of Encodable.encode(to:) + 32 9 SwiftData 0x24e1cd500 0x24e14c000 + 529664 10 SwiftData 0x24e1cd0c8 0x24e14c000 + 528584 11 SwiftData 0x24e1da960 0x24e14c000 + 584032 12 SwiftData 0x24e1ee2ec 0x24e14c000 + 664300 13 SwiftData 0x24e1d97d8 0x24e14c000 + 579544 14 SwiftData 0x24e1eada0 0x24e14c000 + 650656 15 SwiftData 0x24e1d989c 0x24e14c000 + 579740 16 SwiftData 0x24e1eee78 0x24e14c000 + 667256 17 Impact 0x1027403bc 0x10268c000 + 738236
2
2
212
Oct ’24
SQLLite 3 and iOS 18
Hi, I've got an app using SQLLite. Under iOS 17 I could insert and select rows with no issues. Under iOS 18 the same code runs without errors but the select returns no results. Various select statements with and without where clause's, and freshly created database files all behave the same way. Unless... the phone is in developer mode, then it works same as iOS 17. I'm assuming it's some security change, how do we fix it? Same issue with Swift 5 and Swift 6 for context but I don't think its related to Swift. Thanks !
5
0
243
Oct ’24
Swift Data issue with a recursive model class
Dear Apple Developer Forum As the title suggests, I have an issue with Swift Data when I want to modify a property of a recursive model class instance. Please consider the following sample project: import SwiftUI import SwiftData @main struct ISSUEApp: App { var sharedModelContainer: ModelContainer = { let schema = Schema([ Item.self, ]) let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: true) do { return try ModelContainer(for: schema, configurations: [modelConfiguration]) } catch { fatalError("Could not create ModelContainer: \(error)") } }() var body: some Scene { WindowGroup { ContentView() } .modelContainer(sharedModelContainer) } } @Model final class Item { var name: String? var parent: Item? init(name: String?, parent: Item?) { self.name = name self.parent = parent } } struct ContentView: View { @Environment(\.modelContext) private var context @Query private var items: [Item] @State private var itemToMove: Item? @State private var count: Int = 0 @State private var presentMoveView: Bool = false var body: some View { NavigationStack() { List(items, id: \.id) {item in Button(action: { itemToMove = item }, label: { Text("Id: \(item.name ?? "ERROR") and my parent iD is \(item.parent?.name ?? "root")") .bold(itemToMove == item) .italic(itemToMove == item) }) } .sheet(isPresented: $presentMoveView, content: { MoveView(toMove: self.itemToMove!) }) .toolbar { ToolbarItem(placement: .navigationBarTrailing) { Button(action: { let i = Item(name: "\(count)", parent: nil) context.insert(i) try? context.save() count += 1 }, label: { Text("Add an item") }) } ToolbarItem(placement: .navigationBarLeading) { Button(action: { presentMoveView.toggle() }, label: { Text("Move selected item") }) } } } } } struct MoveView: View { @Environment(\.modelContext) private var modelContext @Environment(\.dismiss) private var dismiss @Query private var items: [Item] @Bindable var toMove: Item @State private var selectedFutureParent: Item? var body: some View { NavigationStack(){ List(items, id: \.id) {item in Button(action: { selectedFutureParent = item }, label: { Text("Id: \(item.name ?? "ERROR") and my parent iD is \(item.parent?.name ?? "root")") .bold(selectedFutureParent == item) .italic(selectedFutureParent == item) }) } .toolbar(){ ToolbarItem{ Button("Move", action: { toMove.parent = selectedFutureParent dismiss() }) } } } } } #Preview { ContentView() .modelContainer(for: Item.self, inMemory: true) } Please launch the preview of this app, add items (as many as you'd like), select one and click on the "Move selected item" button. Select the new parent of the item. As you may have noticed, both selected items (moved item and new parent) are modified, whereas only one equality is used. This issue seems to be independent from the @Bindable property wrapper. I tried many things, such as using index instead of direct elements; using local let constant for the parent but the constant is still modified (very weird...) Thank you in advance for your help ! Best regards
1
0
327
Oct ’24
How can the owner access a zone he shared on cloudkit?
Using this Apple repository as a basis https://github.com/apple/sample-cloudkit-zonesharing I created and verified the shared zone and the same zone is private for the person who shared it and shared for the person who received it, so aren't they the same zones? [same zone but different id?] I can make the person who shared the zone (owner) access the zone as a .shared scope just like the person who was shared.
1
0
214
Oct ’24
CoreData/Database question
I am working on an app that will have about 200mb of data in a database. I would like to install a json file with 3-4 mb on the phone with the app, and then be able to send small packets of information to the user of the app as they are using the app, for example if they hit a button with a link to an instagram page, I can have the database/server send the link to the app, it will be just small bits of information going from the database to the phone, and perhaps I would do some location tracking and getting some information from the user to build up personal preferences etc. I'm wondering if coredata would be the best way to get smaller packets of information to the phone quickly or if I should think about firebase or something else. I was interested in using Cloudkit, but it seems like Cloudkit is really more about syncing devices and for getting information from the user to the database. It's been really hard to find any information about the strengths versus weaknesses of different databases and how they interact with mobile apps.
0
0
170
Oct ’24
Warning in Xcode console: Couldn't read values in CFPrefsPlistSource
I have enabled an App Group in my App and the Widget Extension. I use it to share my UserDefaults. Every time the app starts I now get the following error message in the Xcode console: Couldn't read values in CFPrefsPlistSource<0x303034510> (Domain: group.XX.XXXX.XXXX, User: kCFPreferencesAnyUser, ByHost: Yes, Container: (null), Contents Need Refresh: Yes): Using kCFPreferencesAnyUser with a container is only allowed for System Containers, detaching from cfprefsd The shared UserDefaults itself works without problems. Any ideas how I could get rid of this warning?
1
0
485
Oct ’24
My Swift concurrency is no longer running properly and it's screwing up my SwiftData objects
I have a bug I've come across since I've upgraded Xcode (16.0) and macOS (15.0 Sequoia) and figured I'd create a minimal viable example in case someone else came across this and help. I've noticed this in both the macOS and iOS version of my app when I run it. Essentially I have an area of my code that calls a class that has a step 1 and 2 process. The first step uses async let _ = await methodCall(...) to create some SwiftData items while the second step uses a TaskGroup to go through the created elements, checks if an image is needed, and syncs it. Before this worked great as the first part finished and saved before the second part happened. Now it doesn't see the save and thus doesn't see the insertions/edits/etc in the first part so the second part just isn't done properly. Those step one changes are set and shown in the UI so, in this case, if I run it again the second part works just fine on those previous items while any newly created items are skipped. I came across this issue when step one handled 74 inserts as each one didn't contain an image attached to it. When I switched the async let _ = await methodCall(...) to a TaskGroup, hoping that would wait better and work properly, I had the same issue but now only 10 to 30 items were created from the first step. Minimal Viable Example: to reproduce something similar In my minimal viable sample I simplified it way down so you can't run it twice and it's limited it creating 15 subitems. That said, I've hooked it up with both an async let _ = await methodCall(...) dubbed AL and a TaskGroup dubbed TG. With both types my second process (incrementing the number associated with the subissue/subitem) isn't run as it doesn't see the subitem as having been created and, when run with TaskGroup, only 12 to 15 items are created rather that the always 15 of async let. Code shared here: https://gist.github.com/SimplyKyra/aeee2d43689d907d7a66805ce4bbf072 And this gives a macOS view of showing each time the button is pressed the sub issues created never increment to 1 while, when using TaskGroup, 15 isn't guaranteed to be created and remembered. I'm essentially wondering if anyone else has this issue and if so have you figured out how to solve it? Thanks
2
0
289
Sep ’24
CloudKit error: Client went away before operation XXXXXX could be validated; failing
All of a sudden my app started getting this CloudKit error, and it happens to a lot of users. I had no changes to cloud sync for months and really surprised by seeing this. What confuses me even more, is that there is no information on the web about this kind of error. I have no idea what causes it and how to solve it. Would love to get any feedback from the CloudKit engineer. Client went away before operation 27761871408C460A could be validated; failing { "NSUnderlyingError": "<CKUnderlyingError 0x600002573f30: \"ClientInternalError\" (2005); \"Client went away before operation 27761871408C460A could be validated; failing\">", "CKErrorDescription": "Client went away before operation 27761871408C460A could be validated; failing", "NSDebugDescription": "CKInternalErrorDomain: 2005", "NSLocalizedDescription": "Client went away before operation 27761871408C460A could be validated; failing" } Seems to happen only on macOS.
2
0
377
Sep ’24
Querying modifiedTimestamp in CloudKit
I have a requirement to get all records changed after a certain date. I have set modifiedTimestamp as Queryable, but when I attempt to do any query at all using the following operators: > < >= <= no results are returned. I have confirmed there are records that should be returned. The only operator that works is == and !=. I have tried the following: NSPredicate(format: "modificationDate > %@", lastFetched as NSDate) NSPredicate(format: "___modTime > %@", lastFetched as NSDate)
1
0
284
Sep ’24
Cloudkit issue | development environment
Hello! I deleted an index on the cloudkit console of a container in development environment and re-added it again with the same name. After that my app has been giving error on development environment. The live version is working fine as I haven't deployed the changes.. Any idea what can cause this issue and is there a way to fix it? Thank you
1
0
230
Sep ’24
Core Data modifications not saved in two of three tables
I'm a bit lost because of a problem I never experienced before: I create entries in 3 Core Data tables and link them. As long as the app is open, everything is fine, I can see the database entries in the three tables. Once the App is closed and restarted, however, the new entries in two of the three tables are gone. I use Core Data for data storage and DB Browser for SQLite for inspecting the database running in the Simulator. Here's the relevant function where all Core Data handling happens: /** Creates a new ComposedFoodItem from the ComposedFoodItemViewModel. Creates the related FoodItem and the Ingredients. Creates all relationships. - Parameter composedFoodItemVM: The source view model. - Returns: A Core Data ComposedFoodItem; nil if there are no Ingredients. */ static func create(from composedFoodItemVM: ComposedFoodItemViewModel, generateTypicalAmounts: Bool) -> ComposedFoodItem? { debugPrint(AppDelegate.persistentContainer.persistentStoreDescriptions) // The location of the .sqlite file let moc = AppDelegate.viewContext // Create new ComposedFoodItem (1) let cdComposedFoodItem = ComposedFoodItem(context: moc) // No existing composed food item, therefore create a new UUID cdComposedFoodItem.id = UUID() // Fill data cdComposedFoodItem.amount = Int64(composedFoodItemVM.amount) cdComposedFoodItem.numberOfPortions = Int16(composedFoodItemVM.numberOfPortions) // Create the related FoodItem (2) let cdFoodItem = FoodItem.create(from: composedFoodItemVM, generateTypicalAmounts: generateTypicalAmounts) // Relate both (3) cdComposedFoodItem.foodItem = cdFoodItem // Add cdComposedFoodItem to composedFoodItemVM composedFoodItemVM.cdComposedFoodItem = cdComposedFoodItem // Add new ingredients (4) if let cdIngredients = Ingredient.create(from: composedFoodItemVM) { cdComposedFoodItem.addToIngredients(NSSet(array: cdIngredients)) // Save new composed food item try? moc.save() // Return the ComposedFoodItem return cdComposedFoodItem } else { // There are no ingredients, therefore we delete it again and return nil moc.delete(cdComposedFoodItem) try? moc.save() return nil } } What the function does: Creates a new entry in table ComposedFoodItem Creates another new entry in another table FoodItem Relates both entries Creates another 1..n entries in a third table Ingredient and links these to the entry created in step 1 All this works fine, I can see all relations and entries in the database. Then I quit and restart the app. The entry created in step 2 is still there, but the entries created in steps 1 and 4 are gone, as well as the relationships (of course). My suspicion: I recently implemented a Core Data migration from Data Model version 1 ("EasyFPU") to version 2 ("EasyFPU 2"). In this migration, I have two custom migration policies for exactly the two tables, which are not stored. The migration policies are pretty simple (and identical for both tables): /** No Ingredient is created in the destination model, i.e., there will be no Ingredients */ override func createDestinationInstances(forSource sourceIngredient: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws { // Do nothing on purpose debugPrint("Not migrating Ingredient with ID: \((sourceIngredient as? Ingredient)?.id.uuidString ?? "unknown")") } And what I suspect is, that this migration policies are somehow called when restarting the app, but I have no idea why, because the migration has already happened before. If I set a breakpoint in the debugPrint line of the code snippet above, I actually never reach this breakpoint - as expected. Nevertheless are the two tables Ingredient and ComposedFoodItem empty after restart. My AppDelegate Core Data persistentContainer variable looks like this: lazy var persistentContainer: NSPersistentCloudKitContainer = { let container = NSPersistentCloudKitContainer(name: "EasyFPU") container.loadPersistentStores(completionHandler: { (storeDescription, error) in if let error = error as NSError? { fatalError("Unresolved error \(error), \(error.userInfo)") } }) return container }() I tried to replace "EasyFPU" with "EasyFPU 2", but this apparently is not the version, but the container name. Any idea? Thanks in advance!
1
0
190
Sep ’24