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

CoreData triggers incompatible model error while it shouldn't
Hello. I recently released a new version (2.6) of my CloudKit syncing CoreData based app. The new version uses v18 of my data model. V18 is exactly like v17, except for a new optional string field in one of the entities. I diffed the two model versions to be extra sure. During my test I did not encounter any crash, and I also tested automatic migration, installing 2.55 and building 2.6 on top of it. No troubles. However my crash logger reports a number of crashes among my users. It's not a huge numbers (10 users over about 900 or more) but I am surprised it crashes at all. The crash happens when I call NSPersistentCloudKitContainer.loadPersistentStores, I get this error in the completion block: The model used to open the store is incompatible with the one used to create the store" I always assumed these slight changes (new field added to an existing model) did not require a manual migration. Any suggestions?
1
0
234
Apr ’24
What's the correct way to delete a SwiftData model that is in a many to many relationship?
The deletion is working, but it does not refresh the view. This is similar to a question I asked previously but I started a new test project to try and work this out. @Model class Transaction { var timestamp: Date var note: String @Relationship(deleteRule: .cascade) var items: [Item]? init(timestamp: Date, note: String, items: [Item]? = nil) { self.timestamp = timestamp self.note = note self.items = items } func getModifierCount() -> Int { guard let items = items else { return 0 } return items.reduce(0, {result, item in result + (item.modifiers?.count ?? 0) }) } } @Model class Item { var timestamp: Date var note: String @Relationship(deleteRule: .nullify) var transaction: Transaction? @Relationship(deleteRule: .noAction) var modifiers: [Modifier]? init(timestamp: Date, note: String, transaction: Transaction? = nil, modifiers: [Modifier]? = nil) { self.timestamp = timestamp self.note = note self.transaction = transaction self.modifiers = modifiers } } @Model class Modifier { var timestamp: Date var value: Double @Relationship(deleteRule: .nullify) var items: [Item]? init(timestamp: Date, value: Double, items: [Item]? = nil) { self.timestamp = timestamp self.value = value self.items = items } } struct ContentView: View { @Environment(\.modelContext) private var context @Query private var items: [Item] @Query private var transactions: [Transaction] @Query private var modifiers: [Modifier] @State private var addItem = false @State private var addTransaction = false var body: some View { NavigationStack { List { Section(content: { ForEach(items) { item in LabeledText(label: item.timestamp.formatAsString(), value: .int(item.modifiers?.count ?? -1)) } .onDelete(perform: { indexSet in withAnimation { for index in indexSet { context.delete(items[index]) } } }) }, header: { LabeledView(label: "Items", view: { Button("", systemImage: "plus", action: {}) }) }) Section(content: { ForEach(modifiers) { modifier in LabeledText(label: modifier.timestamp.formatAsString(), value: .currency(modifier.value)) } .onDelete(perform: { indexSet in indexSet.forEach { index in context.delete(modifiers[index]) } }) }, header: { LabeledView(label: "Modifiers", view: { Button("", systemImage: "plus", action: {}) }) }) Section(content: { ForEach(transactions) { transaction in LabeledText(label: transaction.note, value: .int(transaction.getModifierCount())) } .onDelete(perform: { indexSet in withAnimation { for index in indexSet { context.delete(transactions[index]) } } }) }, header: { LabeledView(label: "Transactions", view: { Button("", systemImage: "plus", action: {addTransaction.toggle()}) }) }) } .navigationTitle("Testing") .sheet(isPresented: $addTransaction, content: { TransactionEditor() }) } } } } Here's the scenario. Create a transaction with 1 item. That item will contain 1 modifier. ContentView will display Items, Modifiers, and Transactions. For Item, it will display the date and how many modifiers it has. Modifier will display the date and its value. Transactions will display a date and how many modifiers are contained inside of its items. When I delete a modifier, in this case the only one that exist, I should see the count update to 0 for both the Item and the Transaction. This is not happening unless I close the application and reopen it. If I do that, it's updated to 0. I tried to add an ID variable to the view and change it to force a refresh, but it's not updating. This issue also seems to be only with this many to many relationship. Previously, I only had the Transaction and Item models. Deleting an Item would correctly update Transaction, but that was a one to many relationship. I would like for Modifier to have a many to many relationship with Items, so they can be reused. Why is deleting a modifier not updating the items correctly? Why is this not refreshing the view? How can I resolve this issue?
2
0
309
Apr ’24
SwiftData: Deleting a model is working, but the previous view isn't showing it
I have a TabView which consists of a few different tabs. One of which does an @Query to retrieve an array of Transaction models. These are then displayed in a list using a ForEach. struct TransactionsTab: View { @Query private var transactions: [Transaction] ... other code Section(content: { ForEach(transactions) { transaction in transaction.getListItem() } }, header: { LabeledView(label: "Recent Transactions", view: { ListButton(mode: .link(destination: { ListView(list: transactions) .navigationTitle("All Transactions") })) }) }) Transaction contains a different model called TransactionItem and that has a variable called amount. That amount variable is used in the getListItem() function to show how much the total transaction was in the list item. The issue is that I can delete a Transaction and the ForEach will update to reflect that. However, if I delete an TransactionItem separately, that getListItem() will not show that it's been deleted. The total amount shown will still be as if the TransactionItem was never deleted. It will only update when the app is closed and reopened. Below is the code that's ran when deleting a model, in this case a TransactionItem. // Deletes a single item private func delete() { deleteWarning = false if let item = itemToDelete { // If last item is being delete, dismiss the view if list.count == 1 { dismissView() } context.delete(item) context.saveContext() itemToDelete = nil } mode = .view } I would think that deleting the model and having it save will cause the transaction query to update. What's going on here to cause it to not update? By the way, saveContext() just calls the ModelContext save function. extension ModelContext { func saveContext() { do { try self.save() } catch { print("Could not save context: \(error.localizedDescription)") } } }
0
0
241
Apr ’24
Xcode 15.2b Transformable Properties Crash App
This possibly seems like a regression but from iOS 17.1.0+, I'm having issues from Xcode 15.2 Beta &where when using a transformable property I'm getting a crash when trying to create a model container. This worked fine for me in Xcode 15.1 Beta when testing on iOS OS 17.0.1 and below. I have a simple model where I'm trying to save a UIColor, below is an example of this model. class Category: Codable { @Attribute(.unique) var title: String var items: [Item]? @Attribute(.transformable(by: ColorValueTransformer.self)) var color: UIColor? init(title: String = "", color: UIColor) { self.title = title self.color = color } enum CodingKeys: String, CodingKey { case title } required init(from decoder: Decoder) throws { ... } func encode(to encoder: Encoder) throws { ... } } Within my value transformer, I'm handling setting and getting the value. final class ColorValueTransformer: ValueTransformer { static let name = NSValueTransformerName(rawValue: String(describing: ColorValueTransformer.self)) override func transformedValue(_ value: Any?) -> Any? { guard let color = value as? UIColor else { return nil } do { let data = try NSKeyedArchiver.archivedData(withRootObject: color, requiringSecureCoding: true) return data } catch { return nil } } override func reverseTransformedValue(_ value: Any?) -> Any? { guard let data = value as? Data else { return nil } do { let color = try NSKeyedUnarchiver.unarchivedObject(ofClass: UIColor.self, from: data) return color } catch { return nil } } public static func register() { let transformer = ColorValueTransformer() ValueTransformer.setValueTransformer(transformer, forName: name) } } Then within my root app entry point, I register this transformer. @main struct ToDosApp: App { ...... init() { ColorValueTransformer.register() } ...... Unfortunately in my custom container object I get a crash on this line let container = try ModelContainer(for: ....) With an error of Thread 1: EXC_BAD_ACCESS (code=1, address=0x0) Like i said before previously this was working fine but now it's not... I have a feedback open also FB13471979 but it would be great if someone on the SwiftData team at Apple could look into this issue since it's a pretty big regression...
4
0
781
Dec ’23
Edit Swiftdata data
Dear all, I'm quite new to SwiftUI. I have a view where I'd like to open a sheet to edit data in a List. Here below the code of the view: import SwiftUI import SwiftData struct SettingsView: View { @Query(sort: \Stagione.idStagione) private var usoStagione: [Stagione] @Environment(\.modelContext) private var context @State private var stagione = String(Calendar.current.component(.year, from: Date())) @State private var miaSquadra = "" @State private var categoria = "" @State private var selStagione = Set<Stagione>() @State private var modificaStagione = false var body: some View { NavigationStack { GroupBox("Stagione") { Form { TextField("Stagione:", text: $stagione) .frame(width: 150) TextField("Categoria:", text: $categoria) .frame(width: 400) TextField("Mia squadra:", text: $miaSquadra) .frame(width: 400) Button("Salva") { let nuovaStagione = Stagione(idStagione: stagione, categoriaStagione: categoria, miaSquadra: miaSquadra) context.insert(nuovaStagione) miaSquadra = "" categoria = "" stagione = String(Calendar.current.component(.year, from: Date())) } .frame(maxWidth: .infinity, alignment: .trailing) .buttonStyle(.borderedProminent) .disabled(categoria.isEmpty || miaSquadra.isEmpty) } List(selection: $selStagione) { ForEach(usoStagione, id: \.self) { stag in VStack(alignment: .leading) { Text("\(stag.idStagione)").font(.title2) Text("\(stag.miaSquadra)").foregroundStyle(.secondary) Text("\(stag.categoriaStagione)").foregroundStyle(.secondary) } } .contextMenu() { Button(action: { selStagione.forEach(context.delete) }) { Text("Cancella") } Button(action: { self.modificaStagione = true }) { Text("Modifica") } } } .sheet(isPresented: $modificaStagione) { ModificaStagione(stagione: Stagione) } .listStyle(.plain) .textFieldStyle(.roundedBorder) .padding() } } .padding() .textFieldStyle(.roundedBorder) .navigationTitle("Impostazioni") GroupBox("Squadre") { } } } #Preview { SettingsView() .environmentObject(NavigationStateManager()) .modelContainer(for: Stagione.self, inMemory: true) } While here below the code of the view ModificaStagione: import SwiftUI struct ModificaStagione: View { @Environment(\.dismiss) private var dismiss let stagione: Stagione @State private var idStagione = "" @State private var categoria = "" @State private var miaSquadra = "" @State private var vistaPrecedente = true var body: some View { VStack (alignment: .leading) { GroupBox { LabeledContent { TextField("", text: $categoria) .frame(width: 400) } label: { Text("Categoria:") } LabeledContent { TextField("", text: $miaSquadra) .frame(width: 400) } label: { Text("Mia squadra:") } if modifica { Button("Aggiorna dati") { stagione.idStagione = idStagione stagione.categoriaStagione = categoria stagione.miaSquadra = miaSquadra dismiss() } .buttonStyle(.borderedProminent) } } .padding() .textFieldStyle(.roundedBorder) .navigationTitle("Modifica dati stagione") } .onAppear { idStagione = stagione.idStagione categoria = stagione.categoriaStagione miaSquadra = stagione.miaSquadra } } var modifica: Bool { categoria != stagione.categoriaStagione || miaSquadra != stagione.miaSquadra } } In the "Setting" view I receive an error message when I call the view "Modifica Stagione "saying that "Cannot convert value of type 'Stagione.Type' to expected argument type 'Stagione'". What am I doing wrong? Thanks in advance, A.
1
0
385
Apr ’24
.transformable with ValueTransformer failing after Xcode 15.1 update
In Xcode 15.0.1, I created a new project to start working with SwiftData. I did this by creating a default App project and checking the Use SwiftData checkbox. The resulting project contains just three files: an app entry point file, a ContentView SwiftUI view file, and an Item model file. The only change I made was to annotate the default Item timestamp property with a .transformable attribute. Here is the resulting model: @Model final class Item { @Attribute(.transformable(by: TestVT.self)) var timestamp: Date // Only updated this line init(timestamp: Date) { self.timestamp = timestamp } } And here is the definition of TestVT. It is a basic ValueTransformer that simply tries to store the Date as a NSNumber: // Added this class TestVT: ValueTransformer { static let name = NSValueTransformerName("TestVT") override class func transformedValueClass() -> AnyClass { NSNumber.self } override class func allowsReverseTransformation() -> Bool { true } override func transformedValue(_ value: Any?) -> Any? { guard let date = value as? Date else { return nil } let ti = date.timeIntervalSince1970 return NSNumber(value: ti) } override func reverseTransformedValue(_ value: Any?) -> Any? { guard let num = value as? NSNumber else { return nil } let ti = num.doubleValue as TimeInterval return Date(timeIntervalSince1970: ti) } } And finally, I made sure to register my ValueTransformer but updating the sharedModelContainer definition in the App: var sharedModelContainer: ModelContainer = { ValueTransformer.setValueTransformer(TestVT(), forName: TestVT.name) // Only added this line let schema = Schema([ Item.self, ]) let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false) do { return try ModelContainer(for: schema, configurations: [modelConfiguration]) } catch { fatalError("Could not create ModelContainer: \(error)") } }() Prior to Xcode 15.1, this was working fine. However, now when I try to create an item when running the app I get the following error: Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unacceptable type of value for attribute: property = "timestamp"; desired type = NSNumber; given type = __NSTaggedDate; value = 2023-12-14 01:47:11 +0000.' I'm unsure of why this stopped working. The error seems to be complaining about the input being of type Date when NSNumber was expected, but I thought that's what the ValueTransformer was supposed to be doing. Important note: prior to Xcode 15.1, I did not originally override the transformedValueClass() and everything was working but in the new Xcode when launching the app I was getting a Thread 1: EXC_BAD_ACCESS (code=1, address=0x0) on the return try ModelContainer(...) line. Removing the .transformable property from my model fixed the issue. That's why I added the override here, because I think the docs indicate overriding it as well and I missed that the first time. This being said, I think the code I have is what a correct ValueTransformer would look like. If anyone has experienced this issue, or has a working ValueTransformer for SwiftData in Xcode 15.1, please let me know. Appreciate any help with this issue. Thanks so much!
3
3
824
Dec ’23
SwiftData.framework Info.plist is missing from the project directory
iOS17 using swiftData & CloudKit. compiles correctly, then throws error "App installation failed: Unable To Install " Please try again later. Failed to load Info.plist from bundle at path ... /.../simulatorlocation/.app/Frameworks/SwiftData.framework/Info.plist: No such file or directory. same error occurs on physical device 15Pro running iOS17.5 how do I fix this? here is the error: Please try again later. Failed to load Info.plist from bundle at path /Users//Library/Developer/CoreSimulator/Devices/996C811C-EE2D-47AE-881A-D1D2FA830BCC/data/Library/Caches/com.apple.mobile.installd.staging/temp.kkR2I8/extracted/Payload/.app/Frameworks/SwiftData.framework; Extra info about "/Users//Library/Developer/CoreSimulator/Devices/996C811C-EE2D-47AE-881A-D1D2FA830BCC/data/Library/Caches/com.apple.mobile.installd.staging/temp.kkR2I8/extracted/Payload/.app/Frameworks/SwiftData.framework/Info.plist": Couldn't stat /Users//Library/Developer/CoreSimulator/Devices/996C811C-EE2D-47AE-881A-D1D2FA830BCC/data/Library/Caches/com.apple.mobile.installd.staging/temp.kkR2I8/extracted/Payload/.app/Frameworks/SwiftData.framework/Info.plist: No such file or directory
0
0
236
Apr ’24
Can you have two separate model containers with SwiftData?
Hello. See the code below. struct ContentView: View { var body: some View { TabView { VehicleTab() .tabItem({ Label("Vehicles", systemImage: "car.fill")}) .modelContainer(for: Vehicle.self) TransactionsTab() .tabItem { Label("Transactions", systemImage: "dollarsign") } .modelContainer(for: Transaction.self) } } } Using the .modelContainer() in this way seems to be causing some issue. I was under the assumption that this would just create a container for each view. I get the error below in this configuration. If I comment out either one of the .modelContainer() modifiers, it works fine. Query encountered an error: Error Domain=NSCocoaErrorDomain Code=256 "The file “default.store” couldn’t be opened." Are you not able to do what I'm doing? Is there a way to have two separate containers?
0
0
240
Apr ’24
UIManagedDocument Best Practices
We currently have a shoebox-based architecture but want to transition to a document-based architecture, so UIManagedDocument seems like an obvious choice. However, the UIManagedDocument API seems outdated given the relatively newer NSPersistentContainer API. Also, it’s not clear if UIManagedDocument’s managedObjectContext can be used on the main thread or not. Ideally, I would like to see a persistentContainer property added to UIManagedDocument which could then be used to obtain the view context or a background managed object context. Does anyone have any suggestions on the latest best practices for document-based architectures using CoreData? I’m more interested in Swift implementations, but knowing best practices for SwiftUI and SwiftData would be helpful too.
0
0
262
Apr ’24
SwiftData fetch array only when i needed
I used Query(filter:sortBy:) and show them in the ListView. When I change the property of the model, because I fetched filtered and sorted array, the model immediately reflect the change and find its position. What I want is at initializing it fetches filtered and sorted array. And when I change the property nothing happens. But when I tap on refresh button, then the array should change. For example in ToDoList app, the array consists of not done works. when I tap done, it should stay until I refresh. Is it possible?
1
0
232
Apr ’24
iCloud Drive on iOS extremely slow to load and causing app issues
Previously iCloud Drive worked fine on my iPhone (15 Pro), but within the last couple of months it seems to have died. It continues to work fine on other connected devices (iPad, MBP etc), but will not work on iPhone. This issue seemed to begin roughly around the early 17.4 betas, but was also present in the public release and has continued on to the current 17.5 betas. I initially noticed WhatsApp couldn't back up to iCloud despite all the options being turned on. I assumed this was a WhatsApp issue. But I've recently noticed that Castro hangs on every single load and then crashes. I know that Castro does an initial call to iCloud to check back-ups etc so I went to have a look at iCloud Drive itself on my device - every single time I open Files, iCloud Drive takes 10-15 minutes to load/show anything. So it seems that iCloud Drive is not "holding" any information/content and is then taking an age to load, which is causing these other apps to time-out and crash. Turning off iCloud Drive on the device (a 35 minute waiting process) stops the issues and the apps work fine (aside from now not being able to back-up to iCloud as it's off), but resetting, allowing to re-sync again, does not resolve the issue on the device at all, and if it's turned back on, the apps begin to fail again, and even after a full re-sync it takes 10-15 minutes to load every time. To note; my connection is not an issue, and I have more than enough space on-device to cache/store stuff that's required. Any thoughts on what could be causing the issue and how to resolve?
1
0
664
Apr ’24
TextField Data Saving
Hey Everyone, I am working on this project and it has to be done really soon. I have 30 TextFields and I need it to be saved to the whole app so If I had 1 phone inputting it, it would sync to another one with the same text value in it. So say I put "Done" in one TextField on Phone 1 then it'll save and update on Phone 2. Please get back to me when someone can. I have been developing in Xcode for about 7 months now and I am just running into it right now! Thanks so much
2
0
260
Apr ’24
Advice for AppSupport to AppGroup migration before publishing
Hi all In pursuit of adopting widgets in my application, I have transitioned from AppSupport to AppGroup as storage location for Core Data. I have done a migration process/flow that goes as follows and which have been tested multiple times although I have yet to publish the update: Check if migration has taken place or not 1a. if yes continue to app 1b. If no continue flow Begin migration process 2a. Backup original store in AppSupport 2b. Migrate store to AppGroup 2c. Migrate userdefaults to AppGroup 2d. Update userdefaults with true for both hasMigratedToAppGroup and hasMigratedUserDefaultsToAppGroup Is there any tips or stuff to look for that hasn’t been taken in to account? How have you done it previously, and what would be recommended? Also, is there some specific tests to run/over many times get a baseline of how many is succeeding or failing? Thanks in advance.
4
0
553
Feb ’24
CloudKit notifications no longer working
I have an app that relies on CloudKit notifications for a core feature, but for about a week now the app is not receiving any CloudKit notifications. This follows a week in which I received "status 500" errors from CloudKit and my app was rendered useless. Those errors mysteriously stopped happening, but my app is still hindered by the lack of CloudKit notifications. I have not gotten any response from Apple on this, despite several attempts through various channels. It's not tenable to build apps that users rely on based on a platform that is so unreliable, and for which support is essentially nonexistent. To any CloudKit developers reading this: Please follow up with me so that I can resolve these issues for my users.
5
0
300
Apr ’24
iCloud Documents content is kept during App Transfer?
Hello, we are planning to migrate an app that uses iCloud documents to store some documents that the user can upload/download and modify. In the official overview of App Transfer here, there are information related to CloudKit Containers and KVS but nothing related to iCloud Documents. The content of iCloud Documents is accessed using FileManager.default.url(forUbiquityContainerIdentifier: containerID) where the containerID has the form iCloud.com.things.things, even if in the official documentation it is written that the identifier must be prefixed with the Team ID. With this ID the storage works properly and we never experienced problems. Do you know if migrating an app with this functionality can be problematic? Do you know if the Team ID is somehow used even if not explicitly passed in the call to the function? Thank you and have a nice day!
0
0
372
Apr ’24
Advantages Of SwiftData
What sets the SwiftData framework apart from traditional iOS data storage solutions like Core Data or Realm? Could you elaborate on SwiftData's unique features and architecture that enable developers to efficiently manage data in their Swift projects? How does SwiftData enhance the development experience by seamlessly integrating with Swift's language features and paradigms
3
0
389
Apr ’24