Swiftui View and @Fetchrequest Predicate With Variable That Can Change

SwiftUI View and @FetchRequest predicate with variable that can change

had the same problem, and a comment of Brad Dillon showed the solution:

var predicate:String
var wordsRequest : FetchRequest<Word>
var words : FetchedResults<Word>{wordsRequest.wrappedValue}

init(predicate:String){
self.predicate = predicate
self.wordsRequest = FetchRequest(entity: Word.entity(), sortDescriptors: [], predicate:
NSPredicate(format: "%K == %@", #keyPath(Word.character),predicate))

}

in this example, you can modify the predicate in the initializer.

@FetchRequest predicate not updating when UserDefaults value changes SwiftUI

I would update the fetch request with a new predicate in the Button action and that update should trigger the request to be executed again

struct ContentView: View {
@AppStorage("showAvailable") private var showAvailable : Bool = false

@FetchRequest(sortDescriptors: [],
predicate: NSPredicate(value: true)
animation: .default)
private var list: FetchedResults<Item>

var body: some View {
Button("Cancel") {
showAvailable.toggle()
updatePredicate()
}
.onAppear {
updatePredicate()
}
}

private func updatePredicate() {
if showAvailable {
list.nspredicate = NSPredicate(format: "parent == nil")
} else {
list.nspredicate = NSPredicate(value: true)
}
}
}

SwiftUI - Use value passed from previous view in predicate

You just need to declare the variable in the header. You can then do the initialization in the init() and use the variable that is passed in. If you aren't subsequently needing series, you do not need to have any variable in the view to assign it to. Also, as you didn't post your full view, I had to guess at the type of series.

struct ItemAddView: View {
@Environment(\.managedObjectContext) private var viewContext

@FetchRequest private var items: FetchedResults<Item>


init(series: Series) {
let request = Item.fetchRequest(sortDescriptors: [NSSortDescriptor(keyPath: \Item.name, ascending: true)], predicate: NSPredicate(format: "series = %@ AND amount > 0", series), animation: .default)
_items = FetchRequest(fetchRequest: request)

// Initialize anything else that is necessary
}

...
}

SwiftUI use relationship predicate with struct parameter in FetchRequest

Figured it out:

var todoList: TodoList
@FetchRequest var todoItems: FetchedResults<TodoItem>

init(todoList: TodoList) {
self.todoList = todoList
self._todoItems = FetchRequest(
entity: TodoItem.entity(),
sortDescriptors: [NSSortDescriptor(key: "order", ascending: true)],
predicate: NSPredicate(format: "todoList == %@", todoList)
)
}

Thanks to similar answers here: SwiftUI View and @FetchRequest predicate with variable that can change

SwiftUI - how to update data with fetchRequest in init

So, I found a way of solving my problem.

What was the problem?

The View was not updating because I wasn't using FetchRequest property wrapper, because I need a instance variable in that FetchRequest. So I need to do the Fetching inside my Init() method. But what I did was, I just fetched my items once in the init() and that won't be updated unless the parent with is reloaded.

How to solve it without annoying parent update?

Instead of doing a manual fetch only once in the init() I used a FetchRequest and initialized it in the init(), so it still behaves as FetchRequest property wrapper, like an Observable Object.

I declared it like that:

@FetchRequest var articleRows : FetchedResults<Article>

And inside the init()

//Here in my predicate I use self.type variable 
var predicate = NSPredicate(format: "type == %d", self.type)

//Intialize the FetchRequest property wrapper
self._articleRows = FetchRequest(entity: Article.entity(), sortDescriptors: [], predicate: predicate)

Unreliable update with @FetchRequest predicate filtering on UUID typed attributes?

I believe the weird behaviour is due to your predicate, which is being evaluated in two different ways. When you first run the app, or after closing and restarting, the predicate is parsed and passed to SQLite (as a WHERE clause in a SELECT statement). Thereafter, when you add new items, the predicate is evaluated directly in memory (ie in the NSManagedObjectContext) - no need to involve SQLite.

In your predicate, you are comparing a UUID type attribute with a String value - which fails. Even if the string representation of the UUID attribute is the same as the string you compare it with, the context sees them as different and regards the new object as failing the predicate. Hence the view is not updated.

However, SQLite is much more tolerant of type mismatches. (I'm guessing CoreData's implementation of UUID attributes is to store the string representation - but that's just a guess). So when you quit and restart, the fetch is processed by SQLite which regards the new object as meeting the predicate and accordingly includes it in the results.

To get the correct behaviour, I think you need your predicate to compare the UUID attribute with the UUID which has the correct string representation:

NSPredicate(format: "number == %@ OR uuid == %@", NSNumber(5), UUID(uuidString: ItemList.filterUUID))


Related Topics



Leave a reply



Submit