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

SwiftData does not work on a background Task even inside a custom ModelActor.
I have created an actor for the ModelContainer, in order to perform a data load when starting the app in the background. For this I have conformed to the ModelActor protocol and created the necessary elements, even preparing for test data. Then I create a function of type async throws to perform the database loading processes and everything works fine, in that the data is loaded and when loaded it is displayed reactively. actor Container: ModelActor { nonisolated let modelContainer: ModelContainer nonisolated let modelExecutor: ModelExecutor static let modelContainer: ModelContainer = { do { return try ModelContainer(for: Empleados.self) } catch { fatalError() } }() let context: ModelContext init(container: ModelContainer = Container.modelContainer) { self.modelContainer = container let context = ModelContext(modelContainer) self.modelExecutor = DefaultSerialModelExecutor(modelContext: context) self.context = context Task { do { try await loadData() } catch { print("Error en la carga \(error)") } } } } The problem is that, in spite of doing the load inside a Task and that there is no problem, when starting the app it stops responding the UI while loading to the user interactions. Which gives me to understand that actually the task that should be in a background thread is running somehow over the MainActor. As I have my own API that will provide the information to my app and refresh it at each startup or even send them in Batch when the internet connection is lost and comes back, I don't want the user to be continuously noticing that the app stops because it is performing a heavy process that is not really running in the background. Tested and compiled on Xcode 15 beta 7. I made a Feedback for this: FB13038621. Thanks Julio César
8
1
5.8k
Aug ’23
'ID' is inaccessible due to '@_spi' protection level
When I reference the ID of a SwiftData model entity (aka PersistentIdentifier) anywhere as a type (like @State var selection: Set<SomeEntity.ID> = Set<SomeEntity.ID>()) I now get the following error: 'ID' is inaccessible due to '@_spi' protection level This never was a problem with CoreData and also not with SwiftData until the Xcode 15 RC. Does anybody know, if this is a bug or intended behaviour?
3
2
1.6k
Sep ’23
SwiftData @Query crashes when trying to filter or sort using an enum or relationship
Like the title says, I've realised that when I try to use filter or sort on properties that aren't standard supported data types i.e. Using a transformable or a value type like an enum, I seem to be getting the following crash... SwiftData/DataUtilities.swift:1140: Fatal error: Unexpected type for Expansion: Optional<UIColor> Xcode expands and shows me when trying to access the wrapped value it's crashing. I'm assumung that the query property wrapper can't handle these custom data types @Query private var items: [Item] { get { _items.wrappedValue <--- Crash here } } Which seems to be pointing to a transferable property in one of my models. Below are my two models i'm using. enum Priority: Int, Codable, Identifiable, CaseIterable { case low case medium case high var title: String { switch self { case .low: return "Low" case .medium: return "Medium" case .high: return "High" } } var image: Image? { switch self { case .medium: return Image(systemName: "exclamationmark.2") case .high: return Image(systemName: "exclamationmark.3") default: return nil } } var id: Self { self } } @Model final class Item: Codable { var title: String @Attribute(originalName: "timestamp") var dueDate: Date var isCompleted: Bool var isFlagged: Bool = false var isArchived: Bool = false var isCritical: Bool? var priority: Priority? @Relationship(deleteRule: .nullify, inverse: \Category.items) var category: Category? @Attribute(.externalStorage) var image: Data? enum CodingKeys: String, CodingKey { case title case timestamp case isCritical case isCompleted case category case imageName } init(title: String = "", dueDate: Date = .now, priority: Priority? = nil, isCompleted: Bool = false) { self.title = title self.dueDate = dueDate self.priority = priority self.isCompleted = isCompleted } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.title = try container.decode(String.self, forKey: .title) self.dueDate = Date.randomDateNextWeek() ?? .now self.isCompleted = try container.decode(Bool.self, forKey: .isCompleted) self.category = try container.decodeIfPresent(Category.self, forKey: .category) if let imageName = try container.decodeIfPresent(String.self, forKey: .imageName), let imageData = UIImage(named: imageName) { self.image = imageData.jpegData(compressionQuality: 0.8) } if let isCritical = try container.decodeIfPresent(Bool.self, forKey: .isCritical), isCritical == true { self.priority = .high } } func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(title, forKey: .title) try container.encode(dueDate, forKey: .timestamp) try container.encode(isCompleted, forKey: .isCompleted) try container.encode(category, forKey: .category) } } @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 { let container = try decoder.container(keyedBy: CodingKeys.self) self.title = try container.decode(String.self, forKey: .title) self.color = UIColor(possibleColors.randomElement()!) } func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(title, forKey: .title) } } And below is an example of me sorting based on my enum (Priority) & Relationship (Category name) func sort() -> [SortDescriptor<Item>]{ switch self { case .title: [SortDescriptor(\Item.title)] case .date: [SortDescriptor(\Item.dueDate)] case .category: [SortDescriptor(\Item.category?.title)] case .priority: [SortDescriptor(\Item.priority?.rawValue)] } } And a filter example below creating a predicate that we will execute to return and matches found in the title or category title let highPriority = Priority.high if let query { return #Predicate { $0.priority == highPriority && ($0.title.contains(query) || $0.category?.title.contains(query) == true) && $0.isArchived == false } } I'm pretty sure this is a SwiftData bug since when using strings, bools and dates it's all fine using anything outside of that box causes these crashes...
8
1
2.7k
Sep ’23
Custom struct Codable for SwiftData
I'm encountering an issue encoding/decoding a custom struct from SwiftData. As it's all happening behind the generated code of SwiftData and a decoder, I'm not really sure what's going on. I have a custom type defined kind of like this: public struct Group<Key: Hashable, Element: Hashable> { private var elementGroups: [Element: Key] private var groupedElements: [Key: [Element]] } In short, it allows multiple elements (usually a string), to be grouped, referenced by some key. I have Codable conformance to this object, so I can encode and decode it. For simplicity, the elementGroups is encoded/decoded, and the groupedElements is rebuilt when decoding. My implementation is similar to this: extension Group: Codable where Key: Codable, Element: Codable { private enum Keys: CodingKey { case groups } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: Keys.self) let decoded = try container.decode([Element: Key].self, forKey: .groups) // Enumerate over the element groups, and populate the list of elements. // var elements: [Key: [Element]] = [:] for group in decoded { elements[group.value] = (elements[group.value] ?? []) + [group.key] } elementGroups = decoded groupedElements = elements } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: Keys.self) try container.encode(elementGroups, forKey: .groups) } } This works fine when encoding and decoding to JSON, but when I attempt to use this structure as a value within a SwiftData model, then decoding the type crashes my application. @Model final class MyModel { var id: UUID = UUID() var groups: Group<UUID, String> = Group<UUID, String>() init(id: UUID) { self.id = id } } When something attempts to decode the groups property on the MyModel object, it crashes with the following error: Could not cast value of type 'Swift.Optional<Any>' (0x1ed7d0290) to 'Swift.Dictionary<Swift.String, Foundation.UUID>' (0x121fa9448). I would guess that there is a nil value stored for groups in SwiftData, and attempting to decode it to a Group<UUID, String> type is failing. It's odd that it doesn't throw an exception though, and hard crashes. Also, I'm not sure why it's optional, as a value is being written out. Does anyone have any ideas?
4
1
1.3k
Oct ’23
Swift Data value is duplicated between two variables in a class
I'm using two loops, one nested in another to create and assign a subclass to the parent class. I'm using x for one loop and y for the other loop. Print statement shows the loop variables being updated correctly, however the subclass has both variables as the same value. I'm not sure if the value is being stored as the same value or being displayed as the same value. I've checked both creation and display code. I can't find the error. var body: some View { NavigationSplitView { List { ForEach(routes) { item in NavigationLink { Text("Route: \(item.route_name) \nSeason: \(item.route_season)\nCoordinates: \(item.route_coordinates)\nProcessed: \(String(item.route_processed))\nNumber of baseboards: \(item.route_baseboards.count)") } label: { Text(item.route_name) } //end route nav link } //end route for each .onDelete(perform: deleteItems) //end route nav ForEach(baseboards) { item in NavigationLink { //if let test = item.baseboard_heightPoints.count { Text("Grid Size: \(String(item.baseboard_grid_size))\nRow:\(String(item.baseboard_row))\nColumn:\(String(item.baseboard_column))\nHeight Point Count:")//\(String(item.baseboard_heightPoints.flatMap { $0 } .count))") //fix count later //Text("Test") // Text("test2") // } else { // Text("Grid Size: \(String(item.baseboard_grid_size))\nRow:\(String(item.baseboard_row))\nColumn:\(String(item.baseboard_column))\nHeight Point Count: 0") // } } label: { Text(String(item.baseboard_grid_size)) }} .onDelete(perform: deleteItemsBaseboards) //end baseboard route nav // ForEach(heightPoints) { item in NavigationLink { // Text("Row:\(String(item.hp_row))\nColumn:\(String(item.hp_column))\nElevation:\(String(item.hp_elevation))") // } label: { // Text("Row:\(String(item.hp_row))\nColumn:\(String(item.hp_column))") // }} //.onDelete(perform: deleteItemsBaseboards) } .toolbar { ToolbarItem { Button(action: addItem) { Label("Add Route", systemImage: "plus") } //Button(action: addItem) { //not showing up // Label("Add Baseboard", systemImage: "arrow.up") //} } } //end toolbar } detail: { Text("Select a route") } //end NavigationSplitView } //end view body private func addItem() { /*withAnimation { */ let newItem = Route( route_name: "test route " + UUID().uuidString, route_season: "summer", route_processed: false, route_coordinates: "Somewhere", route_region: "US", route_baseboards: []) modelContext.insert(newItem) //end add route //add baseboards to each route let bb_StartCol = 0 let bb_EndCol = 3 let bb_StartRow = 0 let bb_EndRow = 3 //let grid5m = 148 //let grid10m = 76 //let gridHD = 5760 var bb_grid_size = 5760 let bb_sectionsVerticle = 180 let bb_sectionsHorizonal = 360 var sectionData: Data var dataInputArray: [UInt8] = [0x03, 0x00, 0x00, 0x00, 0x00, 0x82, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x20, 0xF8, 0xFF] sectionData = Data(withUnsafeBytes(of: dataInputArray, Array.init)) for x in bb_StartCol...bb_EndCol { //columns for y in bb_StartRow...bb_EndRow { //rows print(x,y) if bb_grid_size < 1000 { let newItem2 = Baseboard( baseboard_column: Int16(x), baseboard_row: Int16(y), texture: "Grid", baseboard_processed: false, baseboard_grid_size: Int16(bb_grid_size),//(x+2)+(y+2), baseboard_heightPoints: Array(repeating: Array(repeating: 0, count: bb_grid_size), count: bb_grid_size), baseboard_HPSection: [], baseboard_route: newItem //baseboard_hps: [] ) modelContext.insert(newItem2) //insert baseboard for each run } else { let newItem2 = Baseboard( baseboard_column: Int16(x), baseboard_row: Int16(y), texture: "Grid", baseboard_processed: false, baseboard_grid_size: Int16(bb_grid_size),//(x+2)+(y+2), baseboard_heightPoints: [], baseboard_HPSection: Array(repeating: Array(repeating: sectionData, count: bb_sectionsVerticle), count: bb_sectionsHorizonal), baseboard_route: newItem //baseboard_hps: [] ) modelContext.insert(newItem2) //insert baseboard for each run } //print(x,y) } //end y for loop - baseboards } //end x for loop - baseboards // } // end animation of adding new items } // end function add items private func deleteItems(offsets: IndexSet) { withAnimation { for index in offsets { modelContext.delete(routes[index]) } } } private func deleteItemsBaseboards(offsets: IndexSet) { withAnimation { for index in offsets { modelContext.delete(baseboards[index]) } } } //private func deleteItemsHeightPoints(offsets: IndexSet) { // withAnimation { // for index in offsets { // modelContext.delete(heightPoints[index]) // } // } // } } #Preview { ContentView() .modelContainer(for: Route.self, inMemory: false) }
3
0
824
Oct ’23
CloudKit Console - Internal Error during Query Records
Issue: I'm experiencing intermittent CloudKit Console 'Internal Error' when performing simple queries on a Private database. I am experiencing this issue with multiple CloudKit databases. In all instances, the issue is intermittent. Steps to Replicate in the CloudKit Console: Select a Database Select Records Select Private Database Select Custom Zone Select Record Type Select Query Records IF the records populate, click 'Query Records' again until Internal Error occurs. Expected Results: A list of records Actual Results: 'Internal Error' (see screenshot below) Additional Info: Starting last month, I started receiving CKCloudKit Error 15 when attempting to sync data from a private CloudKit database. My query code has not changed for a few years now with no previous issues. I believe these errors are the 'same' and on the Apple Server side. Is anyone else experiencing this issue? Any help would be greatly appreciated. Thank you.
3
2
1.1k
Oct ’23
Added new field to swiftdata model, now crashes
I had a simple class called Entry with one field (timestamp: Date) and I tried to add a new field without having to uninstall the app , so I would not crash. I tried implementing the MigrationPlan stuff but I do not know if I have to manually add a value to the new field or how exactly it works. Here is my code. When I use the EntrySchemaV0 it works fine but if I try to use the V1 it crashes. (could not fetch ModelContainer) I also tried it with a custom migration stage. Crashes with error (SwiftData/BackingData.swift:432: Fatal error: Expected only Arrays for Relationships - String) import Foundation import SwiftData enum EntrySchemaV0: VersionedSchema { static var versionIdentifier = Schema.Version(0, 1, 0) static var models: [any PersistentModel.Type] { [Entry.self] } @Model final class Entry { var timestamp: Date init(timestamp: Date) { self.timestamp = timestamp } } } enum EntrySchemaV1: VersionedSchema { static var versionIdentifier = Schema.Version(0, 2, 0) static var models: [any PersistentModel.Type] { [Entry.self] } @Model final class Entry { var name: String var timestamp: Date init(name: String = "", timestamp: Date = .now) { self.name = name self.timestamp = timestamp } } } enum EntryMigrationPlan: SchemaMigrationPlan { static var schemas: [any VersionedSchema.Type] { [EntrySchemaV0.self, EntrySchemaV1.self] } static var stages: [MigrationStage] { [migrateV0toV1] } static let migrateV0toV1 = MigrationStage.lightweight( fromVersion: EntrySchemaV0.self, toVersion: EntrySchemaV1.self ) }
3
3
1.4k
Oct ’23
SwiftData Schema Migration Plan when the type of a field in your model changes
Hi I am trying to figure out how to properly migrate my schema when a field in my model needs to become a different type. I start with a simple model User with an array of type String called friends @Model final class User { @Attribute(.unique) var id: String var friends: [String]? } Now I want to change the type of friends to [User]? but I am unsure how to make a migration plan for this. I created two versioned schemas enum UserSchemaV1: VersionedSchema { static var versionIdentifier = Schema.Version(1, 0, 0) static var models: [any PersistentModel.Type] { [User.self] } @Model final class User { @Attribute(.unique) var id: String var friends: [String]? } } enum UserSchemaV2: VersionedSchema { static var versionIdentifier = Schema.Version(2, 0, 0) static var models: [any PersistentModel.Type] { [User.self] } @Model final class User { @Attribute(.unique) var id: String var friends: [User]? } } Then I make a migration plan enum UsersMigrationPlan: SchemaMigrationPlan { static var stages: [MigrationStage] { [migrateV1toV2] } static var schemas: [any VersionedSchema.Type] { [UserSchemaV1.self, UserSchemaV2.self] } static let migrateV1toV2 = MigrationStage.custom( fromVersion: UserSchemaV1.self, toVersion: UserSchemaV2.self, willMigrate: nil, didMigrate: nil ) } And I make a container using my migration plan let container: ModelContainer init() { do { container = try ModelContainer(for: User.self, migrationPlan: UsersMigrationPlan.self ) } catch { fatalError("Failed to initialize user model container") } } I also use a typealias so I can keep using User in my code typealias User = UserSchemaV2.User But no matter what I try I get an error when running my code Thread 1: Fatal error: Unknown related type - User In the closure for v2 of the Schema set { _$observationRegistrar.withMutation(of: self, keyPath: \.friends) { self.setValue(forKey: \.friends, to: newValue) } } What am I misunderstanding about migrating my schema with this change? Is this something that's possible when doing a schema migration? Is there a simple/better/easier way to modify my schema to change the type of the field?
1
0
1.1k
Nov ’23
Selecting which data models sync with iCloud SwiftData
So I am trying to sync only some of my Models with iCloud and others kept locally in the default.store. I am having a world of issues so before I start looking for the needle in my haystack. I would like to ask this forum, is my approach one that should work as desired or is my code obviously why things are not working? All my Models have default values and relationships where needed are optionals. iCloud is working but my issue arises when i try to exclude some models. So I want to sync "modelsForCloudSyncing" but not "modelNotForCloudSyncing" In advance thank you var avoidCloudSyncModelContainer : ModelContainer = { let modelNotForCloudSyncing = Schema([NoCloudSyncModel.self]) let modelConfigForNoCloudSync = ModelConfiguration(schema: modelNotForCloudSyncing, cloudKitDatabase: .none) let modelsForCloudSyncing = Schema([CloudSyncModelA.self, CloudSyncModelB.self, CloudSyncModelC.self]) let modelConfigForCloudSync = ModelConfiguration(schema: modelsForCloudSyncing, cloudKitDatabase: .automatic) do { return try ModelContainer(for: NoCloudSyncModel.self, CloudSyncModelA.self, CloudSyncModelB.self, CloudSyncModelC.self, configurations: modelConfigForNoCloudSync, modelConfigForCloudSync) } catch { fatalError("Could not create ModelContainer: \(error)") } }() ... { ContentView() }.modelContainer(avoidCloudSyncModelContainer)
11
2
1.8k
Nov ’23
SwiftData PersistentIdentifier saved to UserDefaults?
Hi, I'm updating my app from CoreData to SwiftData and came across an issue. My app has multiple users so in CoreData and I assigned each a myID value set to an UUID so I could use UserDefaults to set the preferred user on app load. When switching over I noticed the PersistentIdentifier value and got excited as I could fetch the matching entity with modelContext.model(for: yourID). I decided to use that instead so I updated my UserDefaults code from UUID to this: @Published var selectedUserID: PersistentIdentifier? { didSet { UserDefaults.standard.set(selectedUserID, forKey: "selectedUserID") } } init() { self.selectedUserID = UserDefaults.standard.object(forKey: "selectedUserID") as? PersistentIdentifier ?? nil } This code compiles and, of course the id is currently set to nil. My issue now is when I try to assign a user to it ar my app crashes and I get the following error: Attempt to set a non-property-list object SwiftData.PersistentIdentifier(id: SwiftData.PersistentIdentifier.ID(url: x-coredata://6FE80FC9-0B4C-491E-8093-DED37A619F1B/EnteredUser/p834), implementation: SwiftData.PersistentIdentifierImplementation) as an NSUserDefaults/CFPreferences value for key selectedUserID Should I go back to an additional UUID field in my user model and find it that way or is there a way to use the PersistentIdentifier value with my UserDefaults? Thanks for any tips.
4
0
1k
Nov ’23
How could I lose access to my app's bundle ID?
We're doing some disaster recovery management / risk management and a point-of-failure for our app is if we lose access to our bundle id. From my understanding, secure keychain items are scoped to your bundle ID as well as iCloud files stored under the app with 'hidden' scope. Losing our bundle ID is a scenario we want to eliminate completely from our threat/disaster modelling. Is this a realistic concern we should have?
2
0
600
Nov ’23
SwiftData CloudKit integration seems to log out or deregister
Friends, I have created an App in SwiftData that uses CloudKit to sync between devices. I am using Xcode 15.0.1, and iOS 17.1.1. For further context, I am calling modelContext.save() with every change that I want to synchronise, and this seems to call a CloudKit save, as expected, within the development environment. The synchronisation works great in the development environment with no issues, it updates fairly quickly and I use @Query to manage SwiftUI updates in the most direct way possible. It is a complex model with many relationships, and I call @Query and filter instances to get to the instance required, rather than using traditional Bindings, as many tutorials and WWDC have suggested. When I switch to the production environment the app synchronises between devices great using the production CloudKit container. I have set up push notification certificates, and these seem to work. The issues is that, after a few minutes, the synchronisation stops happening between devices. When synchronisation is working, Device 1 initially saves to CloudKit, and you can see the items update in the CloudKit console. When synching stops working, Device 1 stops saving, and the CloudKit console stops updating. If I then delete and install the app on Device 1 from TestFlight, you can see that it starts saving again, with updates to the CloudKit console as expected. But, Device 2 does not begin updating again unless you delete the app on that device, and install again. This behaviour seems to suggest that both devices become logged out or deregistered from CloudKit after a short period of time as a consequence of some unknown process within CloudKit or SwiftData. When logged out, each device cannot write to, or read from, CloudKit. Now, the problem with trying to fix the issue is that the registration with CloudKit, silent push notifications, and fetches, are all managed "under the hood" by SwiftData. In the production environment, you cannot configure any registration state or refresh registration within your code, because you don't have access to the parts of SwiftData that manage this. I wanted to find out if this is an issue that has been encountered by other users, and if anyone can help with a solution, or perhaps a debugging strategy that I can use to find out what is happening. Thank you all in advance.
3
1
1.2k
Nov ’23
SwiftData deleteRule .cascade
I made simple school & student model with RelationShip import SwiftUI import SwiftData @Model final class School { var name: String @Relationship(deleteRule: .cascade, inverse: \Student.school) var studentList: [Student] = [Student]() init(name: String) { self.name = name } } @Model final class Student { var name: String var school: School? init(name: String) { self.name = name } } ~ struct SchoolView: View { @Environment(\.modelContext) private var modelContext @Query(sort: \School.name) var schools: [School] @Query(sort: \Student.name) var students: [Student] var body: some View { NavigationStack { List { ForEach(schools) { school in NavigationLink { StudentView(school: school) } label: { HStack { Text(school.name) Spacer() Text("\(school.studentList.count)") } } .swipeActions { Button(role: .destructive) { deleteSchool(school) } label: { Label("Delete", systemImage: "trash") } } } .onDelete(perform: deleteSchools(at:)) } .navigationTitle("Home") .listStyle(.plain) .toolbar { ToolbarItem(placement: .topBarTrailing) { Button { addSchool() } label: { Image(systemName: "plus") } } ToolbarItem(placement: .topBarLeading) { VStack(alignment: .leading) { Text("School: \(schools.count)") Text("Student: \(students.count)") } } } } } private func randomString() -> String { let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" return String((0..<5).map { _ in letters.randomElement()! }) } private func addSchool() { let newSchool = School(name: randomString()) modelContext.insert(newSchool) } private func deleteSchools(at offsets: IndexSet) { offsets.map { schools[$0] }.forEach(deleteSchool) } private func deleteSchool(_ school: School) { modelContext.delete(school) try? modelContext.save() } } struct StudentView: View { @Environment(\.modelContext) private var modelContext var school: School var body: some View { List { ForEach(school.studentList) { student in Text(student.name) } .onDelete(perform: deleteStudents(at:)) } .navigationTitle("Home") .navigationBarTitleDisplayMode(.inline) .listStyle(.plain) .toolbar { ToolbarItem(placement: .topBarTrailing) { Button { addStudent() } label: { Image(systemName: "plus") } } } } private func addStudent() { let newSchool = Student(name: randomString()) modelContext.insert(newSchool) newSchool.school = school school.studentList.append(newSchool) } private func randomString() -> String { let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" return String((0..<5).map { _ in letters.randomElement()! }) } private func deleteStudents(at offsets: IndexSet) { withAnimation { offsets.forEach { let student = school.studentList[$0] modelContext.delete(student) try? modelContext.save() } } } } I try my best to follow the SampleTrips app from Apple developer. When I delete one of the schools, then all the students in the school should be deleted. But the student count never changes. Deleting the student itself works well - the student count decreases. Thank you!
0
0
561
Nov ’23
Huge increase in CKErrorServerRejectedRequest / CKHTTPStatus=503 errors
Hi, My app has been receiving a huge increase in the number of CKHTTPStatus=503 errors over the past couple of months. I created a thread before, and also a Feedback (FB13300807) over a month ago, but I haven't gotten any assistance on this, and am wondering if there is any better way to get the attention of a CloudKit engineer who might be able to help. From my users, I was able to print out the error code and error userInfo in the console: error.code == 15 (the same as CKErrorServerRejectedRequest), UserInfo={ContainerID=, CKHTTPStatus=503, RequestUUID=17C6B9B9-35DD-411B-8AED-7A497075D228, OperationID=5285362CCD2DDB32}}, CKHTTPStatus=503} How can I get this issue addressed? A lot of users are reporting this issue and it's creating a big support burden.
1
0
408
Nov ’23
Name clashes with SwiftData classes
I have a shopping list app and the data model is very simple, just 5 entities. These have names List, Product, Item, Section and Data. For CoreData I was able to use the auto-generated classes and gave my own names for the classes (prefixing my entity names with CD - e.g CDList) However with SwiftData I don't have that capability. My @Model classes are named List, Data etc and obviously these clash with the standard Swift/SwiftUI classes. Even the much quoted example app has the same issue a task todo list with an entity named Task, which would clash with Swift's own Task class. Is the correct/only approach that I don't use the @Model macro but roll my own SwiftData classes - e.g inline the macros, or is there a way I can give the @Model classes my own name (e.g SDList, and leave the CoreData entity names as they are). I don't really want to rename my entities if at all avoidable.
2
1
652
Dec ’23
How to resolve unexpected behavior in SwiftData LinkedList
I tried to practice SwiftData by creating a LinkedList. However, contrary to my expectations. even though a.next == b but b.next != nil, b.next == a. Why is that? @Environment(\.modelContext) private var modelContext @Query private var items: [Item] Button { var a = Item(value: 0) var b = Item(value: 1) a.next = b modelContext.insert(a) } label: { Text("+++") } @Model final class Item { var value: Int weak var next: Item? init(value: Int, next: Item? = nil) { self.value = value self.next = next } } this is whole code import SwiftUI import SwiftData struct ContentView: View { @Environment(\.modelContext) private var modelContext @Query private var items: [Item] var body: some View { ZStack { VStack { ForEach(items){item in Button { modelContext.delete(item) } label: { Text(String(item.value)) } } } } VStack { Button { var a = Item(value: 0) var b = Item(value: 1) a.next = b modelContext.insert(a) // modelContext.insert(b) // let fetch = FetchDescriptor<Item>( // predicate: #Predicate{$0.value == 0} // ) // let data = try! modelContext.fetch(fetch) // data[0].next = b } label: { Text("+++") } Button { for i in items { modelContext.delete(i) } } label: { Text("---") } Button { for i in items { print(i.value) print(i.next) } } label: { Text("Print") } } } } #Preview { ContentView() .modelContainer(for: Item.self, inMemory: true) }
2
0
243
Dec ’23
CloudKit Erasing Private Database with No Errors?!
Starting today around 2PM MST I started receiving emails from users reporting their CloudKit synced data was 'completely gone'... They are reporting no error messages... so that means the CKQuery on the private database is completing without error, but simply not returning any previously saved records... This appears to be only occurring to a percentage of my users and I cannot replicate it on my device (I'm using iOS 17.1.2. Are any other developers experiencing this?!
0
0
372
Dec ’23