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

NSPersistentCloudKitContainer migration with custom NSEntityMigrationPolicy
Recently, I have made quite extensive changes to my schema and need to migrate my CoreData + CloudKit model to a new version. The changes require me to use a custom NSEntityMigrationPolicy because I have a rather complex mapping between some old entities and new entities. I have added a new model version. Deleted some entities, and added some entities. I have defined the NSEntityMigrationPolicy with createDestinationInstances(forSource:in:manager:) and createRelationships(forDestination:in:manager:). I have created a new Core Data Mapping Model. This was probably unnecessary. Within the Core Data Mapping Model, I have specified Custom Policy for all entities. In my container setup, I added two options, as below: storeDescription.setOption(false as NSNumber, forKey: NSMigratePersistentStoresAutomaticallyOption) storeDescription.setOption(false as NSNumber, forKey: NSInferMappingModelAutomaticallyOption) I mostly followed a "Core Data Heavyweight Migration" guide. I'm unable to share the link, but it can be quite easily found on the web. (It's not for CloudKit specifically.) When I run my app, I am getting the most basic of errors, which is: The managed object model version used to open the persistent store is incompatible with the one that was used to create the persistent store. So I guess that migration wasn't even attempted, which makes sense because I set NSMigratePersistentStoresAutomaticallyOption to false. I tried to go beyond what I could find on the web and attempted to manually initialize migration: let sourceModel = container.persistentStoreCoordinator.managedObjectModel guard let modelURL = Bundle.main.url(forResource: "MyModelName", withExtension: "xcdatamodeld") else { fatalError("Unable to locate model file.") } guard let destinationModel = NSManagedObjectModel(contentsOf: modelURL) else { fatalError("Unable to load destination model.") } let migrationManager = NSMigrationManager(sourceModel: sourceModel, destinationModel: destinationModel) let mappingModel = NSMappingModel(from: [Bundle.main], forSourceModel: sourceModel, destinationModel: destinationModel)! migrationManager.currentEntityMapping.entityMigrationPolicyClassName = "MyMigrationPolicyClassName" I am then stuck at the migrateStore(from:type:mapping:to:type:) method. It seems to target only local storage, not CloudKit. Otherwise, what do I provide for URLs and types? Any guidance for custom logic CoreData with CloudKit migration would be greatly appreciated.
1
0
267
May ’24
SwiftData public sharing
I have an Apple app that uses SwiftData and icloud to sync the App's data across users' devices. Everything is working well. However, I am facing the following issue: SwiftData does not support public sharing of the object graph with other users via iCloud. How can I overcome this limitation without stopping using SwiftData? Thanks in advance!
1
3
259
May ’24
Can a private database entity have a relationship to a public database entity?
I’m using NSPersistentCloudKitContainer and I’m utilising the public database and also the user’s private database. For example I have an entity called Category which has a many-to-many relationship to an entity called NewsArticle. So the NewsArticles exist in the public database for the user to browse, but he can add them to a category which will live in his private database. So that’s my question, is it possible for an entity which exists a in the private database to have a relationship to another entity in a public database?
1
1
615
May ’23
SwiftData modelContainer Error
It's been frustrating to solve this error. My iOS device and Xcode are fully updated. I can easily run app on simulator, but issue happens on my iPhone. dyld[23479]: Symbol not found: _$s9SwiftData12ModelContextC6insert6objectyx_tAA010PersistentC0RzlFTj Referenced from: <6FC773BB-E68B-35A9-B334-3FFC8B951A4E> Expected in: /System/Library/Frameworks/SwiftData.framework/SwiftData
2
3
892
Aug ’23
Not able to perform read and write operations in iCloud in .Net MAUI Mac
I have set up the app identifier in Apple developer with the document URL set up for iCloud and also updated the info.plist file and entitlements according to this. info.plist <dict> <key>iCloud.com.abc.MyApp</key> <dict> <key>NSUbiquitousContainerIsDocumentScopePublic</key> <true/> <key>NSUbiquitousContainerName</key> <string>MyApp</string> <key>NSUbiquitousContainerSupportedFolderLevels</key> <string>Any</string> </dict> </dict> <key>UIFileSharingEnabled</key> <true/> <key>LSSupportsOpeningDocumentsInPlace</key> <true/> <key>UIBackgroundModes</key> <array> <string>fetch</string> <string>remote-notification</string> </array> <key>NSUbiquitousContainersUsageDescription</key> <string>This app uses iCloud containers to store and sync documents.</string> Entitlement.plist <array> <string>iCloud.com.abc.MyApp</string> </array> <key>com.apple.developer.icloud-services</key> <array> <string>CloudDocuments</string> </array> <key>com.apple.developer.ubiquity-container-identifiers</key> <array> <string>iCloud.com.abc.MyApp</string> </array> // Then I am using iCloud for CRUD operation in the app // Code snippet { try { var iCloudDocumentsURL = NSFileManager.DefaultManager.GetUrlForUbiquityContainer(null); if (iCloudDocumentsURL != null) { var path = iCloudDocumentsURL.ToString().Replace("%C3%97", "x"); var filepath = path.Replace("file://", string.Empty).Replace("%20", " "); var destinationdirectoryPath = Path.combine(filePath,"MyAppDocuments"); if (Directory.Exists(destinationdirectoryPath)) { Directory.Delete(destinationdirectoryPath, recursive: true); } } }catch(Exception ex) { LogHandler.LogError(ex); } } But in Delete operation gives Exception -> System.IO.IOException: Access to the path '/Users/USERABC/Library/Mobile Documents/iCloudcomabc~MyApp/MyAppDocuments' is denied.
0
0
284
May ’24
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
586
Oct ’23
@Query macro vs Query struct
I have spent hours trying to get @Query macros to compile. Mostly they throw up meaningless errors for example the following produces 3 compiler errors: @Query var stylesheets: [StyleSheet] Here's the expansion. The compiler complains that 'private' can't be used here, and it can't find _stylesheets. I searched everywhere to find a resolution then I came across the Query struct. I used it as follows to replace the @Query: let query = Query(FetchDescriptor<StyleSheet>(), animation: .smooth) let styleSheets = query.wrappedValue This also solves another issue that was bugging me - how to get the context when the environment variable is often rejected. All I need to do now is write: let context = query.modelContext None of the WWDC23 SwiftData videos mentions the use of the struct, which is a shame. It feels much like the CoreData approach to fetching data. I hope this helps some of you.
1
0
318
May ’24
CloudKit Private Database Record Zone Limit
I am following this document from Apple to implement sharing with CloudKit. In it, Apple says NSPersistentCloudKitContainer uses CloudKit zone sharing to share objects. Each share has its own record zone on the CloudKit server. CloudKit has a limit on how many record zones a database can have. What is the record zone limit for a private CloudKit database? I can find information about record and participant limits but not on record zone limits.
1
0
154
May ’24
Autocomplete with SwiftData
Dear all, I'm building an app leveraging SwiftData and I have the following two classes: Stagione: import SwiftData @Model class Stagione { @Attribute(.unique) var idStagione: String var categoriaStagione: String var miaSquadra: String @Relationship(deleteRule: .cascade) var rosa: [Rosa]? @Relationship(deleteRule: .cascade) var squadra: [Squadre]? @Relationship(deleteRule: .cascade) var partita: [CalendarioPartite]? init(idStagione: String, categoriaStagione: String, miaSquadra: String) { self.idStagione = idStagione self.categoriaStagione = categoriaStagione self.miaSquadra = miaSquadra } } Squadre: import SwiftData @Model class Squadre { var squadraCampionato: String var stagione: Stagione? init(squadraCampionato: String) { self.squadraCampionato = squadraCampionato } } Now, I have a view in which I'm calling a sheet to insert some Squadre: // Presenta il foglio per aggiungere una nuova partita GroupBox(label: Text("Dettagli Partita").font(.headline).padding()) { VStack { HStack { Text("Giornata:") TextField("Giornata", text: $idGiornata) .frame(width: 30) .textFieldStyle(RoundedBorderTextFieldStyle()) .padding() } DatePicker("Data Partita:", selection: $dataPartita, displayedComponents: .date) .padding() HStack { Text("Squadra Casa:") .frame(width: 150) TextField("Squadra Casa", text: $squadraCasa) .textFieldStyle(RoundedBorderTextFieldStyle()) .padding() TextField("Gol Casa", text: $golCasa) .textFieldStyle(RoundedBorderTextFieldStyle()) .padding() } HStack { Text("Squadra Trasferta:") .frame(width: 150) TextField("Squadra Trasferta", text: $squadraTrasferta) .textFieldStyle(RoundedBorderTextFieldStyle()) .padding() TextField("Gol Trasferta", text: $golTrasferta) .textFieldStyle(RoundedBorderTextFieldStyle()) .padding() } HStack { Button("Salva") { if let partitaSelezionata = partitaSelezionata { // Se è stata selezionata una partita, aggiorna i suoi dati if let index = partite.firstIndex(where: { $0.id == partitaSelezionata.id }) { partite[index].idGiornata = Int(idGiornata) ?? 0 partite[index].dataPartita = dataPartita partite[index].squadraCasa = squadraCasa partite[index].golCasa = Int(golCasa) ?? 0 partite[index].squadraTrasferta = squadraTrasferta partite[index].golTrasferta = Int(golTrasferta) ?? 0 } } else { // Altrimenti, aggiungi una nuova partita aggiungiPartita(stagione: stagione) } // Chiudi il foglio di presentazione mostraAggiungiPartita = false // Resetta il campo di input idGiornata = "" dataPartita = Date() squadraCasa = "" golCasa = "" squadraTrasferta = "" golTrasferta = "" } .buttonStyle(.borderedProminent) .disabled(idGiornata.isEmpty || squadraCasa.isEmpty || squadraTrasferta.isEmpty || golCasa.isEmpty || golTrasferta.isEmpty) // Bottone Chiudi Button("Chiudi") { mostraAggiungiPartita = false } .buttonStyle(.borderedProminent) } } .padding() } } I'd like to insert a autocomplete function in the textfields "Squadra Casa" and "Squadra Trasferta", based on the list of Squadre contained in the class "Squadre" and filtered for a specific Stagione. Has anybody of you made something similar? Do you have any suggestions or code example which I can use? Thanks, A.
2
0
256
May ’24
Differentiate whether NSPersistentStoreRemoteChange notification is coming from Cloud or a local change
How can we identify whether the remote change notification is triggered because some data was changed on a different device and it is downloaded from CloudKit, or it is triggered from the current device because new entity was saved into database. Because this notification is posted when both remote data is downloaded or local data is created. It would be great if there is a way to understand the origin of the notification.
0
0
321
May ’24
Unable to load CloudKit CoreData Store
I have a CoreData model, in a Swift Package with tests. I can successfully run the tests, when I load the model using NSPersistentContainer, however attempting this with NSPersistentCloudKitContainer always fails in the call to loadPersistentStores(completionHandler block: @escaping (NSPersistentStoreDescription, Error?) -> Void) The error is : [CK] BUG IN CLIENT OF CLOUDKIT: Not entitled to listen to push notifications. Please add the 'aps-connection-initiate' entitlement. This issue is described on StackOverflow however, the accepted solution does not appear to work in my case. I have tried adding the aps-connection-initiate key to my App Info.plist, the Test Info.plist and the SPM bundle. No change. (NB. adding this to the entitlements file just breaks auto signing). I have enabled App entitlements for App Groups, Remote Notifications background mode, Push Notifications and iCloud CloudKit with a store identifier. I have checked my model. All relationships have inverses. No unique constraints, etc. etc. I am sharing a Bundle ID with a previous version of the App, that also uses CoreData+CloudKit, each version has it's own Model and container identifier, each container identifier is available in the provisioning profile. The new version of the model has two NSPersistentStoreDescriptions, one is configured for CloudKit, the other is a local cache. I am completely stuck, suggestions would be very welcome.
3
1
1.4k
Dec ’22
SwiftData nested models crash upon trying to access nested data.
I am new to swift. This is my Item.swift. import SwiftData @Model final class Item: Codable { var id: String var soundId: String var soundAppleId: String var soundType: String var type: String var authorId: String var text: String var createdAt: Date var actionsCount: Int var chainsCount: Int var rating: Int var loved: Bool var replay: Bool var heartedByUser: Bool @Relationship var author: Author? init(id: String, soundId: String, soundAppleId: String, soundType: String, type: String, authorId: String, text: String, createdAt: Date, actionsCount: Int, chainsCount: Int, ratings: Int, loved: Bool, replay: Bool, heartedByUser: Bool, author: Author) { self.id = id self.soundId = soundId self.soundAppleId = soundAppleId self.soundType = soundType self.type = type self.authorId = authorId self.text = text self.createdAt = createdAt self.actionsCount = actionsCount self.chainsCount = chainsCount self.rating = ratings self.loved = loved self.replay = replay self.heartedByUser = heartedByUser self.author = author } private enum CodingKeys: String, CodingKey { case id case soundId = "sound_id" case soundAppleId = "sound_apple_id" case soundType = "sound_type" case type case authorId = "author_id" case text case createdAt = "created_at" case actionsCount = "actions_count" case chainsCount = "chains_count" case rating case loved case replay case heartedByUser case author } required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) id = try container.decode(String.self, forKey: .id) soundId = try container.decode(String.self, forKey: .soundId) soundAppleId = try container.decode(String.self, forKey: .soundAppleId) soundType = try container.decode(String.self, forKey: .soundType) type = try container.decode(String.self, forKey: .type) authorId = try container.decode(String.self, forKey: .authorId) text = try container.decode(String.self, forKey: .text) let dateString = try container.decode(String.self, forKey: .createdAt) let formatter = DateFormatter() formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" if let date = formatter.date(from: dateString) { createdAt = date } else { throw DecodingError.dataCorruptedError(forKey: .createdAt, in: container, debugDescription: "Date string does not match format expected by formatter.") } actionsCount = try container.decode(Int.self, forKey: .actionsCount) chainsCount = try container.decode(Int.self, forKey: .chainsCount) rating = try container.decode(Int.self, forKey: .rating) loved = try container.decode(Bool.self, forKey: .loved) replay = try container.decode(Bool.self, forKey: .replay) heartedByUser = try container.decode(Bool.self, forKey: .heartedByUser) author = try container.decode(Author.self, forKey: .author) } func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(id, forKey: .id) try container.encode(soundId, forKey: .soundId) try container.encode(soundAppleId, forKey: .soundAppleId) try container.encode(soundType, forKey: .soundType) try container.encode(type, forKey: .type) try container.encode(authorId, forKey: .authorId) try container.encode(text, forKey: .text) let formatter = DateFormatter() formatter.dateFormat = "yyyy-MM-dd" let dateString = formatter.string(from: createdAt) try container.encode(dateString, forKey: .createdAt) try container.encode(actionsCount, forKey: .actionsCount) try container.encode(chainsCount, forKey: .chainsCount) try container.encode(rating, forKey: .rating) try container.encode(loved, forKey: .loved) try container.encode(replay, forKey: .replay) try container.encode(heartedByUser, forKey: .heartedByUser) try container.encode(author, forKey: .author) } } @Model final class Author: Codable { var id: String var image: URL var username: String var bio: String? init(id: String, image: URL, username: String, bio: String?) { self.id = id self.image = image self.username = username self.bio = bio } private enum CodingKeys: String, CodingKey { case id case image case username case bio } required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) id = try container.decode(String.self, forKey: .id) image = try container.decode(URL.self, forKey: .image) username = try container.decode(String.self, forKey: .username) bio = try container.decodeIfPresent(String.self, forKey: .bio) } func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(id, forKey: .id) try container.encode(image, forKey: .image) try container.encode(username, forKey: .username) try container.encodeIfPresent(bio, forKey: .bio) } } In my ItemView when I try to access something inside author, Swift preview crashes. Thread 0 Crashed:: Dispatch queue: com.apple.main-thread 0 SwiftData 0x1cb459e90 0x1cb3d3000 + 552592 1 SwiftData 0x1cb45ba7c 0x1cb3d3000 + 559740 2 SwiftData 0x1cb45e5f8 0x1cb3d3000 + 570872 3 SwiftData 0x1cb4190e4 0x1cb3d3000 + 286948 4 audition 0x100b436e0 Item.author.getter + 320 (@__swiftmacro_8audition4ItemC6author18_PersistedPropertyfMa_.swift:9) 5 ContentView.1.preview-thunk.dylib 0x105f23a20 closure #1 in closure #1 in closure #1 in closure #1 in ItemCard.__preview__body.getter + 820 (ContentView.swift:89) 6 SwiftUI 0x1cba41308 0x1cb47b000 + 6054664 7 ContentView.1.preview-thunk.dylib 0x105f22ee4 closure #1 in closure #1 in closure #1 in ItemCard.__preview__body.getter + 472 (ContentView.swift:84) 8 SwiftUI 0x1cc2e6c40 0x1cb47b000 + 15121472 9 ContentView.1.preview-thunk.dylib 0x105f228b8 closure #1 in closure #1 in ItemCard.__preview__body.getter + 388 (ContentView.swift:83) ...
3
1
308
Apr ’24
Widget error integrate it with CloudKit
A few months back, I launched an app that operated solely on a local level. Recently, I've begun the process of integrating it with CloudKit, and so far, the model integration has been successful. I've utilized SwiftData for this task, making it relatively straightforward to adjust the models, as shown below: ` @Relationship(deleteRule: .cascade, inverse: \ItemForCategory.category) var itemForCategory : [ItemForCategory]? = [ItemForCategory]() ` In my initial version of the code, the widget functioned perfectly. However, I've encountered an error recently stating Missing return in instance method expected to return 'ItemForCategory?'. @MainActor private func getLastItem () -> ItemForCategory? { guard let modelContainer = try? ModelContainer(for: Category.self) else { return nil } let descriptor = FetchDescriptor<Category>() let appCategories = try? modelContainer.mainContext.fetch(descriptor) let lastItem = appCategories?.compactMap { $0.itemForCategory }.last return lastItem } The error surfaces at the return line of code. I'm hopeful that someone can assist me in resolving this issue. Thank you very much.
0
0
208
Apr ’24
ForEach complaining about duplicate values with SwiftData using Unique attribute
I have a Category model that's defined like so: @Model final class Category { @Attribute(.unique) var id: UUID var name: String var parent_id: UUID? //categories can be children of other categories init(id: UUID, name: String, parent_id: UUID?) { self.id = id self.name = name self.parent_id = parent_id } } And I'm getting my categories from an API call and putting it into my View: import SwiftUI import SwiftData struct CategoryView: View { @Environment(\.modelContext) private var modelContext @Query private var categories: [Category] @Query(filter: #Predicate<Category>{ $0.parent_id == nil }) private var top_level_categories: [Category] var spacing: CGFloat = 25 var body: some View { HStack() { Text("Categories") .font(.title.bold()) Spacer() Text("see all") } .padding([.bottom, .top], 0) VStack(spacing: 20) { ScrollView(.horizontal) { HStack(spacing: spacing) { ForEach(top_level_categories) { category in Text(category.name!) } } } } .onAppear{ getCategories() } } func getCategories() { get_refresh_token { token in guard let token = token else { return } var urlRequest = URLRequest (url: URL(string:"https://api.test.com/categories")!) urlRequest.httpMethod = "GET" urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type") urlRequest.addValue("Bearer \(token)", forHTTPHeaderField: "Authorization") URLSession.shared .dataTask(with: urlRequest) { (data, response, error) in do { if let data = data { let c = try JSONDecoder().decode([Category].self, from: data) c.forEach { modelContext.insert($0) } try? modelContext.save() } } catch { print(error) } }.resume() } } } This runs fine the first time I run the app but when I run it again, I get the following error: ForEach<Array<Category>, UUID, Text>: the ID XXXXXX-XXXX-XXXX-XXXX-XXXXXX occurs multiple times within the collection, this will give undefined results! Not sure why this is happening since I thought putting the @Attribute(.unique) on ID means that the same category won't get added twice?
1
0
253
Apr ’24
How to save stories
I am currently writing an app that is about writing stories. As of now, it is fairly simple: ContentView is your "Collection" of stories. PopupView is when you click on a button in ContentView. In popup view you enter the story title. Once you do that, you are brought to a blank page which is StoryView, where the NavigationTitle is what your story title is. Once I finish the story and leave the page / StoryView, it is still there, but once I close the app on my phone and reopen it, the story is gone and is not saved. I am a relatively new developer, so ive been relying on ChatGPT and Google Gemini for the saving parts of this, but it rarely works, and the furthest ive gotten with it is that it saves the story title but doesn't save the content of the story. I have a feeling that the AI is overdoing it as well. If anyone could help, please do so. Ive been trying to fix this for days. If you need me to provide any code, I am happy to do so. [Edited by Moderator]
0
0
236
Apr ’24
CoreData: error: Row (pk = 1) for entity 'ResidentInfo' is missing mandatory text data for property 'name'
I know that this has been posted many times, but I am facing an issue where I can't save a model instance. I know that this is due to enums from others trying to find solutions. The error that shows: CoreData: error: Row (pk = 2) for entity 'ResidentInfo' is missing mandatory text data for property 'name' Solutions that I've tried: removed all enums from their respective structs to being standalone. making sure all enum calls use the full keyPath removing CustomStringConvertible from all enums and moving them to rawValue strings updating Xcode to 15.4b probably other things I've forgotten at this point File is too long to fit in post or comments (I'm sorry it's insanely long, it's a complex model), so I'll try to fit what I can where, are there anythings that stand out that may be an issue? Enums: enum Gender: String, CaseIterable, Codable { case male = "Male" case female = "Female" case transmale = "Trans Male" case transfemale = "Trans Female" case nonbinary = "Nonbinary" case other = "Other" } enum BodyBuild: String, CaseIterable, Codable { case small = "Small" case medium = "Medium" case large = "Large" } enum Status: String, Codable { case incomplete, complete } enum HairColor: String, CaseIterable, Codable { case black = "Black" case blonde = "Blonde" case dirtyBlonde = "Dirty Blonde" case brown = "Brown" case lightBrown = "Light Brown" case darkBrown = "Dark Brown" case red = "Red" } enum EyeColor: String, CaseIterable, Codable { case blue = "Blue" case brown = "Brown" case black = "Black" case green = "Green" case hazel = "Hazel" case gray = "Gray" case heterochromatic = "Heterochromatic" } enum RaceEthnicity: String, CaseIterable, Codable { case native = "American Indian or Alaska Native" case asian = "Asian" case black = "Black or African American" case pi = "Native Hawaiian or Other Pacific Islander" case white = "White" case mixed = "2 or More Races/Mixed" } enum MarkType: String, CaseIterable, Codable { case birthMark = "Birth Mark" case scar = "Scar" case tattoo = "Tattoo" case piercing = "Piercing" case other = "Other" } enum heightFormatStyle: String { case short, long, hash } enum suicideRiskLevel: String, Codable { case low = "Low" case medium = "Medium" case high = "High" } enum MedicationFrequency: String, CaseIterable, Codable { case daily = "Daily" case weekly = "Weekly" case biweekly = "Bi-Weekly" case monthly = "Monthly" case asNeeded = "As Needed" case temporary = "Temporary Use" case other = "Other" } enum SchoolOption: String, CaseIterable, Codable { case ged = "GED" case communityCollege = "Community College" case university = "4-Year College" } enum FamilyDiseaseTypes: String, CaseIterable, Codable { case alcoholism = "Alcoholism" case asthma = "Asthma" case cancer = "Cancer" case drugAbuse = "Drug Abuse" case hypertension = "High Blood Pressure" case nervousBreakdown = "Nervous Breakdown" case sca = "Sickle Cell Anemia" case seizures = "Convulsions, Seizures Epilepsy" case allergies = "Allergies" case birthDefect = "Birth Defect" case diabetes = "Diabetes" case heartDisease = "Heart Disease" case migraines = "Migraine Headaches" case obesity = "Obesity" case tuberculosis = "Tuberculosis" case thyroid = "Glandular/Thyroid Issues" } Structs: struct IdentifyingInformation: Codable { var hairColor: HairColor = HairColor.black var height: Height = Height(feet: 5, inches: 8) var race: RaceEthnicity = RaceEthnicity.native var build: BodyBuild = BodyBuild.small var eyeColor: EyeColor = EyeColor.blue var hispanic: Bool = false var distinguishingMarks: [DistinguishingMark] = [] var currentLivingSitutation: String = "" var currentSupportServices: String = "" struct DistinguishingMark: Codable, Identifiable { var id: UUID = UUID() var type: MarkType = MarkType.tattoo var location: String = "" var description: String = "" var photos: [Data] = [] } struct Height: Codable { var feet: Int var inches: Int func formatted(formatStyle: HeightFormatStyle = .short) -> String { switch formatStyle { case HeightFormatStyle.hash: return "\(feet)'\(inches)\"" case HeightFormatStyle.long: return "\(feet) feet \(inches) inches" case HeightFormatStyle.short: return "\(feet)ft \(inches)in" } } } } struct EmergencyNeeds: Codable { var food: Bool = false var shelter: Bool = false var clothing: Bool = false var hygeine: Bool = false var medical: Bool = false var mentalHealth: Bool = false var otherNeeds: String = "" var abuseNeglectAllegations: Bool = false var abuseReport: AbuseReport? = nil struct AbuseReport: Codable { var reportAccepted: Bool = false var whoAccepted: String = "" var reportNumber: String = "" } } struct RiskAssessment: Codable { var selfHarm: Bool = false var selfHarmAttempt: Bool = false var selfHarmExplanation: String? = nil var currentFeelings: String? = nil var dangerToOthers: Bool = false var dangerToOthersExplanation: String? = nil var suicideAssessmentRequired: Bool { return selfHarm || dangerToOthers } } struct SuicideAssessment: Loopable, Codable { var dateCompleted: Date = Date() var familyMember: Bool = false var treatedMentalIllness: Bool = false var chronicIllness: Bool = false var historyOfSelfDestructiveBehavior: Bool = false var recentLoss: Bool = false var isolatedAloneHopeless: Bool = false var goodbyeNoteOrPosessionDelegation: Bool = false var plan: Bool = false var betterOff: Bool = false var wishToDie: Bool = false var manualReview: Bool = false var comments: String = "" var helpCallMade: Bool = false var riskLevel: suicideRiskLevel { let riskScore = try? allProperties().reduce(0) { result, property in if let isTrue = property.value as? Bool, isTrue { return result + 1 } else { return result } } switch riskScore! { case 0 ... 3: return .low case 4 ... 7: return .medium default: return .high } } } [Continued in comments]
2
0
260
Apr ’24