Post

Replies

Boosts

Views

Activity

Reply to @SectionedFetchRequest filtered using an @AppStorage value
IGNORE MY PREVIOUS ANSWER!!! The following is based upon: a really good answer in StackOverflow to this question "SwiftUI View and @FetchRequest predicate with variable that can change", please refer https://stackoverflow.com/a/64200159/1883707. a well written blog "Swift with Majid" specifically this article https://swiftwithmajid.com/2020/01/22/optimizing-views-in-swiftui-using-equatableview/ and in particular his explanation of "Diffing in SwiftUI". This is the correct answer for two main reasons that I can currently identify... This pattern breaks up the larger view into smaller views, which allows SwiftUI to better render and re-render. This pattern breaks out the properties that are used in the SwiftUI diffing algorithm (as noted in the article by Majid) and therefore the fetch request calls are minimised and the predicate that I need for the @AppStorage property is injected into the child view. (I still can't quite get my head entirely around this, but the pattern works perfectly. If you can better explain it, I'd be grateful for an answer or comment.) So here is the code... struct Accounts: View {     @AppStorage("preference_displayArchived") var kDisplayArchived = true     var body: some View {         AccountsView(displayArchived: kDisplayArchived)     } } struct AccountsView: View {     let displayArchived: Bool     var body: some View {         AccountsList(accounts: SectionedFetchRequest(sectionIdentifier: \.sectionTypeName,                                                      sortDescriptors: [                                                         SortDescriptor(\.type?.name, order: .forward),                                                         SortDescriptor(\.sortOrder, order: .forward)                                                      ],                                                      predicate: displayArchived == true ? NSPredicate(value: true) : NSPredicate(format: "isArchived == %@", NSNumber(booleanLiteral: displayArchived)),                                                      animation: .default),                      displayArchived: displayArchived         )     } } struct AccountsList : View {     @SectionedFetchRequest var accounts: SectionedFetchResults<String, PTG_Account>     let displayArchived: Bool     @State private var searchText = String()     var query: Binding<String> {         Binding {             searchText         } set: { newValue in             searchText = newValue             let predicate01 = NSPredicate(format: "nameTensePresent CONTAINS[cd] %@", newValue)             let predicate02 = NSPredicate(format: "nameTensePast CONTAINS[cd] %@", newValue)             let predicateArchived = displayArchived ? NSPredicate(value: true) : NSPredicate(format: "isArchived == %@", NSNumber(booleanLiteral: displayArchived))             let predicateOr = NSCompoundPredicate(orPredicateWithSubpredicates: [predicate01, predicate02])             let predicateAll = NSCompoundPredicate(andPredicateWithSubpredicates: [predicateOr, predicateArchived])             accounts.nsPredicate = newValue.isEmpty ? predicateArchived : predicateAll         }     }     var title: String {         return "Title For Your View"     }     var body: some View {         VStack(spacing: 0) {             ZStack(alignment: .bottom) {                 ScrollViewReader { proxy in                     List { ...                     }                     .onChange(of: displayArchived) { _ in                         searchText = String()                     }                 }                 ListFooter(countListRows: accounts.reduce(0, {$0 + $1.count}))             }         }         .searchable(text: query)         .navigationTitle(title)         .toolbar {             ToolbarItem(placement: .primaryAction) {                 ...             }         }     } } Where @AppStorage("preference_displayArchived") var kDisplayArchived = true is the user setting to display archived files (in this case, in the Account List()). PTG_Account is the class name for a core data entity Account. .isArchived is the entity attribute of type Bool that is used to archive or unarchive an entity record (in this case, for the entity Account).
Sep ’21
Reply to @SectionedFetchRequest filtered using an @AppStorage value
I'm not that pleased with this solution but it works (on iOS only) and until I can find a more elegant method (that also works on macOS), this will have to suffice! Noting that... @AppStorage("preference_displayArchived") var kDisplayArchived = true Using the same call to @SectionedFetchRequest in the question, I need to complete three tasks... 1 - Update the List when it appears and when the value to the preference changes to include a predicate that will effectively filter the SectionedFetchResults (in this case SectionedFetchResults<String, PTG_Event>):    var body: some View { List() { .... }         .onAppear() {         events.nsPredicate = predicateArchived         }        .onChange(of: kDisplayArchived) { _ in             events.nsPredicate = predicateArchived        } } 2 - Add a computer property for predicateArchived:     var predicateArchived: NSPredicate {         kDisplayArchived == true ? NSPredicate(value: true) : NSPredicate(format: "isArchived == %@", NSNumber(booleanLiteral: kDisplayArchived))     } 3 - Finally I also have to update the search to ensure that this app preference is adopted during the search. Building on the code presented to us in WWDC21-10017 (in presentation skip to time 21:29):     @State private var searchText = String()     var query: Binding<String> {         Binding {             searchText         } set: { newValue in             searchText = newValue             let predicate01 = NSPredicate(format: "name CONTAINS[cd] %@", newValue)             let predicate02 = NSPredicate(format: "reference CONTAINS[cd] %@", newValue)             let predicateArchived = kDisplayArchived == true ? NSPredicate(value: true) : NSPredicate(format: "isArchived == %@", NSNumber(booleanLiteral: kDisplayArchived))             let predicateOr = NSCompoundPredicate(orPredicateWithSubpredicates: [predicate01, predicate02])             let predicateAll = NSCompoundPredicate(andPredicateWithSubpredicates: [predicateArchived, predicateOr])             events.nsPredicate = newValue.isEmpty ? nil : predicateAll         }     } NOTES Known issue: after cancelling a search, the List refreshes without a predicate applied. Need to develop a workaround for this inconsistency.
Sep ’21
Reply to Using Table Selection to Populate Other View
It may be easier to present the detail in a sheet... rather than the three column layout you are currently working with? Are you using the row selection option for Table? From the documentation... Supporting Selection in Tables - To make rows of a table selectable, provide a binding to a selection variable. Also sounds like it may be worth submitting a Feedback to Apple to describe the problems you are facing.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Sep ’21
Reply to Using Table Selection to Populate Other View
It may be easier to present the detail in a sheet... rather than the three column layout you are currently working with? Are you using the row selection option for Table? From the documentation... **Supporting Selection in Tables** To make rows of a table selectable, provide a binding to a selection variable. Also sounds like it may be worth submitting a Feedback to Apple to describe the problems you are facing.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Sep ’21
Reply to Cannot find type 'KeyPathComparator' in scope
You've not really identified the context in which the error is appearing, however I can suggest that if it is relation to sorting, then you should replace KeyPathComparator with SortDescriptor. For example... this doesn't work...     @State var sortOrder: [KeyPathComparator<ModelObject>] = [         .init(\.dateCommences, order: SortOrder.forward)     ] ... however this does...     @State var sortOrder: [SortDescriptor<ModelObject>] = [         .init(\.dateCommences, order: SortOrder.forward)     ] where dateCommences is an example property of ModelObject.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Sep ’21
Reply to SwiftUI TextField present integer (Int64) for macOS target
The problem made me realise that I was force unwrapping an Optional, something I knew but didn't fully comprehend in this context. So the entity attribute sortOrder is of type "Integer 64" and checks "Use Scalar Type". On that last point, I want to work with Int64 in my code, not NSNumber. Albeit that the UI isn't perfect, this works...     TextField("Sort Order",               text: Binding(                 get: { String(account.sortOrder) },                 set: { account.sortOrder = Int64($0.filter{ "0123456789".contains($0)}) ?? 0 }               )     ) I removed the force unwrap and instead "Coalesce using '??' to provide a default when the optional value contains 'nil'". This doesn't work...                 set: { account.sortOrder = Int64($0.filter{ "0123456789".contains($0)}) ?? nil } ... because "'nil' is not compatible with expected argument type 'Int64'". When I traverse my way into the automatically generated property file for the Account entity, I find this line of code for sortOrder...     @NSManaged public var sortOrder: Int64 This file cannot edited so, using CodeGen = Class Definition and "Use Scalar Type", I am stuck with Int64. So I guess I need to revisit my understanding of scalar types and how they work with Core Data CodeGen = Class Definition. It would seem that even though I check the "Optional" type option, the object graph and the automatically generated property file includes an Int64 - not Optional<Int64>. As noted above, in my Core Data object graph, I check the "Use Scalar Type" for the entity attribute sortOrder of type "Integer 64". I do this for a number of reasons that I will not go into here - mainly because I spent a lot of time researching this years ago and made a decision then but acknowledge it may be outdated now - so this will force me to review my use of this option in the object graph. FINALLY... Because CodeGen = Class Definition creates an automatically generated property in my Account property file with an entity attribute of scalar type Int64 instead of the (non-scalar) NSNumber (standard use), I must assume that NumberFormatter requires a non-scalar type NSNumber to function. Sure enough, when I uncheck the "Use Scalar Type" checkbox, NumberFormatter works perfectly for both macOS and iOS targets.  Conclusion: NumberFormatter currently (14 Aug 2021) works only with NSNumber.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Aug ’21
Reply to SwiftUI TextField present integer (Int64) for macOS target
Probably shouldn't have included a link for the FB. But I figured out why NumberFormatter is not working for me... In my Core Data object graph and using my example above, the entity sortOrder is an Integer 64 type with "Use Scalar Type" checked. So when CodeGen creates an automatically generated property for my Account class, it does so with an entity attribute of type Int64 (or perhaps more correctly int64_t) instead of the (non-scalar) NSNumber. So from this I can only assume that NumberFormatter requires a non-scalar type NSNumber. I have a few reasons why I use scalar types but I expect that this will prompt me to do two things - update my feedback AND consider whether I transition to using non-scalar types in my SwiftUI code.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Aug ’21
Reply to @SectionedFetchRequest using relationship as sectionIdentifier
As hinted in the error message, you're attempting to cast the type ServiceCategory in a manner that SwiftUI cannot manage. The var sectionIdentifier is expecting a reference to a ServiceCategory as shown in this line ) var sectionedServices: SectionedFetchResults<ServiceCategory?, Service> but instead you are passing the faulted object ID _NSCoreDataTaggedObjectID per your line sectionIdentifier: \Service.serviceCategory, Service.serviceCategory holds a reference to an entity instance... in your situation the ServiceCategory entity. If you place a break point in your code and query the value you'll probably see a reference to a record id for that entity, not the actual entity object. Frankly I'd recommend that you change your approach a little write an extension on your Service entity and include a convenience method to grab this value... extension Service: NSManagedObject { @objc var serviceCategoryName: String {             return self.serviceCategory.name ?? "NO NAME" } } then use this as follows... @SectionedFetchRequest(     sectionIdentifier: \.serviceCategoryName,     sortDescriptors: [       SortDescriptor(\.active, order: .reverse),       SortDescriptor(\.displayText)     ],     predicate: NSPredicate(format: "%K = %d", #keyPath(.active), true),     animation: .default   ) var sectionedServices: SectionedFetchResults<String, Service> Note the change from type ServiceCategory to type String. and in the list... ForEach(sectionedServices) { section in Section(header: Text(section.id)) { ForEach(section) { service in Text(service.displayText ?? "") } } }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Jul ’21
Reply to CodeSign error (nonzero exit code) HELP
Similar issue with Xcode 12 and target macOS 11.x Universal app written in SwiftUI. Suspect the cause of the issue was my late interruption of a build and run command. Not at all certain about this however. Searched A LOT but no other suggestions worked, including deleting keychain items and build folders and creating new certificates and provisioning profiles. The only solution that worked for me was to let Xcode automatically manage signing and to add the script detailed in the answer by @IndustrialDesigner PS for clarity the script was added for the macOS target under "Build Phases" by clicking the + button and selecting "New Run Script Phase", then copying the script into the black script "box" under the Shell/bin/sh line.
Jun ’21
Reply to Using Core Data with SwiftUI App Protocol
@spellcasterdragonborn Hah, Apple uses the underscore to format italic text, so when I type your name in here the underscores cause formatting chaos. Yes, at this current moment in time, I agree with you - there is no need to use @StateObject. So to be clear, at this current moment in time, I understand that ALL WE NEED to access Core Data features throughout our SwiftUI App is an NSManagedObjectContext. To answer your question the long way round... Apple does not let us edit our answers so when I wrote my original answer, this was all fairly new to me. If I could change the answer - as I have in my SwiftUI universal apps that use Core Data - I would change the following...     lazy var persistentContainer: NSPersistentContainer = {...} Change to: &#9;&#9;private lazy var persistentContainer: NSPersistentContainer = {...} My reason is that there are only three properties that I believe should be publicly available in my class implementation of PersistentStore... static let shared, ...and through this one line singleton... var context, to use throughout the app; and func save, for convenience. If you check Apple's response to my forum question with the abstract title "New toolbar appearance in macOS 11", - https://developer.apple.com/forums/thread/650524 you can see their advice "and then your SwiftUI App could hold on to an instance of that (ed. custom) class in a variable." In their response, they also suggest I should watch the SwiftUI Data Essentials - https://developer.apple.com/videos/play/wwdc2020/10040/ WWDC session for inspiration. From my multiple viewings of this session, at the time I deducted that the hint was to use an @StateObject for my PersistentStore class, which is why I included it in my Core Data SwiftUI Xcode projects and in my original answer. It also made it easy for me to call save from the .onChange(of: scenePhase) view modifier. In hindsight and following review of the template that Apple includes in more recent Xcode 12 betas, I was complicating their hint. (As per Apple's beta Core Data template) the instance of that persistent container custom class could be as simple as...     let persistenceController = PersistenceController.shared or, per my previous answer...     let persistentStore = PersistentStore.shared However, at this current moment in time, I would remove the @StateObject instance of my PersistentStore class. Not that I have done that yet in my SwiftUI projects (no reason, just not got around to it). It seems important for me to add subtext here - I am still developing an understanding of how @StateObject property wrapper operates in the App lifecycle, so in the future and with a better understanding, I might change this decision. (PS: I just commented out @StateObject private var persistentStore = PersistentStore.shared in one project as a test and my iOS and macOS targets appear to build and run without issue. There seems to be a minor drop in memory usage, but this is speculative without taking steps to measure it properly.)
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Sep ’20
Reply to Using WebKit Delegates
@JimDovey your quick example is very helpful thank you. Any chance you might be able to explain how to include forward and backward navigation in your example. In func makeUIView(context: Context) -> WKWebView {} I have attempted to include... &#9;&#9;&#9;&#9;view.allowsBackForwardNavigationGestures = true Using your struct Display I can add buttons without too much trouble immediately beneath .navigationBarTitle...         .toolbar {             ToolbarItemGroup(placement: .navigation) {                 Button(action: { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;// action to navigate back here                 }) {                     Image(systemName: "chevron.left")                 }                 Button(action: { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;// action to navigate forward here                 }) {                     Image(systemName: "chevron.right")                 }             }         } It is the code that is required to actually communicate between the SwiftUI View and its WebView: UIViewRepresentable that I'm struggling with.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Aug ’20