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).
Topic:
App & System Services
SubTopic:
iCloud & Data
Tags: