Post

Replies

Boosts

Views

Activity

Reply to Public and Private CK sync failure, macOS mistake = add data before indexing
Problem solved. When compared to another project I’m working on, I noticed something missing from the “Signing & Capabilities” under macOS App Sandbox… Once I checked Outgoing Connections (Client), Xcode created a new entitlements file (oddly named "AppNameDebug.entitlements") and added the setting "Outgoing Network Connections = YES". Following my next build and run, sync to CloudKit databases worked perfectly. Can’t figure why this wasn’t required before. I didn't uncheck this and the previous entitlements file did not contain this line item before. All I can suggest is that I added an #if DEBUG macro to my project around the same time, so maybe this triggered the requirement? #if DEBUG do { // Use the container to initialize the development schema. try container.initializeCloudKitSchema(options: []) } catch { // Handle any errors. } #endif But main problem solved. If anyone has an explanation that would be appreciated.
Jul ’24
Reply to CloudKit Stopped Syncing after adding new Entities
I've had this problem before and I'm currently experiencing this now. My issue is that I neglected to update the Schema indexes for each new Entity to add (what seems to be necessary): modifiedTimestamp - Queryable modifiedTimestamp - Sortable recordName - Queryable Once I have added these indexes to each new Entity, my sync began working again between devices and iCloud. Although recently, making the same mistake, my macOS instance no longer synced and I'm still trying to solve that problem.
Jun ’24
Reply to Cannot migrate store in-place: CloudKit integration forbids renaming
So this wasn't as difficult as it first seemed... As it happened, all that I was required to do to solve this problem was remove the renaming identifier for all model versions subsequent to my model version 8. To be clear, I retained the renaming ID in the model version 8 to change the relationship name from 'foodServes' (v7) to 'foodPortions' (v8), then for every model version 9 onwards (to v13), deleted the renaming ID. New Entity created so I'm happy and no migration errors so CloudKit is happy.
Feb ’22
Reply to Table() structure selection takes Object.ID but how to obtain reference to NSManagedObject from this ID
Here is my answer... Two alternatives: Iterate over the tableSelection, then filter the NSSet where the entity.id equals the tableSelection ID (there will be only one), then iterate over the resulting array of NSManagedObject. Filter the NSSet where the entity.id is in the tableSelection, then iterate over the resulting array of NSManagedObject. Example for option 1: @State private var tableSelection = Set<Action.ID>() ... if let eventActions = event.actions { for actionID in tableSelection { let eventActionsSelected = eventActions.filter { ($0 as! Action).id == actionID } as! [NSManagedObject] for action in eventActionsSelected { // perform some action... e.g. context?.delete(action) } } } Example for option 2: @State private var tableSelection = Set<Action.ID>() ... if let eventActions = event.actions { let eventActionsSelected = eventActions.filter { tableSelection.contains(($0 as! Action).id) } as! [NSManagedObject] for action in eventActionsSelected { // perform some action... e.g. context?.delete(action) } } I prefer Option 2. While there is a bit too much force downcasting for my liking, at least both options work and from here I can improve.
Dec ’21
Reply to Access a raw value for pure enum without using associated type
to provide some additional context to my original post... Here is another enum for which I can access a raw value for an enum, but it is not pure - it has an associated type NSNumber. The significant difference to this enum is that is has an associated type NSNumber and so I can set a typealias RawValue = NSNumber. enum EntityDateFormat: NSNumber, CaseIterable, Identifiable {     typealias RawValue = NSNumber     var id: NSNumber? { self.rawValue }     case dateTime = 0     case dateOnly     case monthYear     case yearOnly     var template: String {         switch self {         case .dateTime:     return Date.templateDDMYHM // e.g. under extension to Date, static let templateDDMYHM: String! = "EEE dd MMM yyyy hh mm"         case .dateOnly:     return Date.templateDDMY         case .monthYear:    return Date.templateMY         case .yearOnly:     return Date.templateY         }     }     var calendarComponent: Calendar.Component {         switch self {       case .dateTime:     return .minute         case .dateOnly:     return .day         case .monthYear:    return .month         case .yearOnly:     return .year         }     }     var title: String {         switch self {         case .dateTime:     return "Date & Time"         case .dateOnly:     return "Date Only"         case .monthYear:    return "Month & Year"         case .yearOnly:     return "Year Only"         }     }     var prefix: String {         switch self {         case .dateTime:     return "At"         case .dateOnly:     return "On"         case .monthYear:    return "In"         case .yearOnly:     return "In"         }     } } Then I use a function to obtain a formatted string, but I use a parameter format of type NSNumber to reference against the enum and obtain a raw value. struct EntityDate {     private let messageError: String = "Error formatting EntityDate"     func from(_ date: Date, withFormat format: NSNumber) -> String {         guard             let calendarComponent = EntityDateFormat(rawValue: format)?.calendarComponent,             let template = EntityDateFormat(rawValue: format)?.template,             let prefix = EntityDateFormat(rawValue: format)?.prefix             else {                 return messageError         }         let dateRounded = date.roundDown(to: calendarComponent)         let dateFormatted = dateRounded.formatAsStringUsing(template: template, forLocale: Locale.current)         return String("\(prefix) \(dateFormatted)")     } Where .roundDown(to:) and formatAsStringUsing(template:, forLocale:) are custom functions under an extension to Date. So as you can see in this last func, rather than having to run the value for the parameter format through a switch statement to obtain the relevant enum value, (using EntityDateFormat(rawValue: format)?) I have three single lines in a guard statement to determine each value I require for my custom Date functions.
Dec ’21
Reply to Access a raw value for pure enum without using associated type
In response to comment by @Claude31, the location of the (second) error message... let test = Taxon(rawValue: nameType) where I am attempting to obtain a reference to one of the values in the enum Taxon. For clarity, this replaces the commented out code - the above noted switch statement in the iteration over setSorted. So eventually with an accessible initialiser, I might develop that line of code to replace the switch statement entirely and it might look something like this... let test = Taxon(rawValue: nameType).formatted(nameComp) although I am not sure that syntax is correct. Also for clarity, the first error message "Enum with raw type cannot have cases with arguments" is against the line that declares the enum Taxon: String {...} (when I attempt to associate a type with the enum).
Dec ’21
Reply to SwiftUI Picker with option for no selection?
I learned almost all I know about SwiftUI Bindings (with Core Data) by reading a blog by Jim Dovey on Core Data Bindings (do a Google search - its worth it). The remainder is a combination of some research and quite a few hours of making mistakes. So when I use Jim's technique to create Extensions on SwiftUI Binding then we end up with something like this... public extension Binding where Value: Equatable { init(_ source: Binding<Value>, deselectTo value: Value) { self.init(get: { source.wrappedValue }, set: { source.wrappedValue = $0 == source.wrappedValue ? value : $0 } ) } } Which can then be used throughout your code like this... Picker("country", selection: Binding($selection, deselectTo: nil)) { ... } OR Picker("country", selection: Binding($selection, deselectTo: someOtherValue)) { ... } OR when using .pickerStyle(.segmented) Picker("country", selection: Binding($selection, deselectTo: -1)) { ... } which sets the index of the segmented style picker to -1 as per the documentation for UISegmentedControl and selectedSegmentIndex. The default value is noSegment (no segment selected) until the user touches a segment. Set this property to -1 to turn off the current selection.
Dec ’21
Reply to @SectionedFetchRequest with hierarchical data structure (maybe OutlineGroup?)
Using the very helpful answer by @nocsi I have the following working solutions... List { ForEach(gardens) { section in     DisclosureGroup(section.id, content: {         ForEach(section) { garden in             NavigationLink(destination: GardenDetail(...),                            tag: garden.uuID!.uuidString,                            selection: $appData.selectedGardens             ) {                 GardenRow(garden: garden,                           selected: garden.uuID?.uuidString == appData.selectedGardens)             }         }     }) } } OR List { ForEach(gardens) { section in     DisclosureGroup(section.id, content: {         ForEach(section) { garden in             NavigationLink(destination: GardenDetail(...),                            tag: garden.uuID!.uuidString,                            selection: $appData.selectedGardens             ) {                 GardenRow(garden: garden,                           selected: garden.uuID?.uuidString == appData.selectedGardens)             }         } }, label: { Text(section.id)     }) } } However this solution... provides only a top level disclosure group, not the cascading outline group style that I was hoping to achieve; does not provide section headers for iOS and macOS; in my humble opinion, does not work as well as the disclosure indicators for iOS and sizeClassHorizontal == .compact that are automatically provided for each section.
Nov ’21
Reply to I can't get my ForEach List to present data from my Core Data store
I'll be straightforward about this... honestly you have created A LOT more work for yourself than needed. Modern SwiftUI projects that use the Core Data framework can handle ALL the notifications for you when you set up your persistence controller properly and use @FetchRequest or @SectionedFetchRequest. Apple has some great tutorials now that make it easier to understand common coding patterns including how to set up a Core Data stack and add and delete rows in a list. My advice would be to start a new SwiftUI project with the Core Data option checked (and "Host In CloudKit" checked if you want to backup / sync to iCloud), then rebuild your project using that template.
Nov ’21
Reply to SectionedFetchRequest not updating order of Sections
I cannot make @SectionedFetchRequest work with a SortDescriptor where the value is obtained from traversing a Core Data entity relationship. Your example: item.name In fact in Xcode Version 13.1 the compiler presents me with the particularly informative "The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions" and subsequently my project/s will not build. SO this is how I get around the issue (using your example)... I add a new attribute named sectionIdentifier of type String or Integer 64 optional (by default) and if Integer 64 then not scalar to the Core Data entity, in your case the entity named Attribute. With Codegen set to Class Definition, Core Data framework automatically creates an NSManagedObject with property type String? or NSNumber? respectively. Wherever the data for an instance of Attribute is entered by the user (or you), add the following .onChange modifier. (where attribute is defined by @ObservedObject var attribute: Attribute) .onChange(of: attribute.item) { changed in // or because we're not using changed, then { _ in     if let item = attribute.item {         let itemOrder = String(format: "%02d", item.order) // if you set sectionIdentifier type as String, OR         let itemOrder = item.order // if you set sectionIdentifier type as Integer 64         attribute.sectionIdentifier = itemOrder     }     else {         attribute.sectionIdentifier = "0" // if you set sectionIdentifier type as String, OR         attribute.sectionIdentifier = 0 // if you set sectionIdentifier type as Integer 64     } } Change a @SectionedFetchRequest to the following (specifically note the first SortDescriptor). @SectionedFetchRequest(sectionIdentifier: \.sectionName,                     sortDescriptors: [                         SortDescriptor(\.sectionIdentifier, order: .reverse),                          SortDescriptor(\.order, order: .reverse)],                      animation: .default ) var attributes: SectionedFetchResults<String, Attribute> This should produce a dynamically changing SectionedFetchResults for var attributes and subsequently update any List or similar view whenever order changes for an instance of Item.
Nov ’21