Core Data Does Not React on Changed Predicate

Core Data does not react on changed predicate

From the NSFetchedResultsController reference:

Important: If you are using a cache, you must call
deleteCacheWithName: before changing any of the fetch request, its
predicate, or its sort descriptors. You must not reuse the same
fetched results controller for multiple queries unless you set the
cacheName to nil.

So the problem in your case is that the FRC re-uses a cache that was created for a
different predicate. Either don't use a cache (cacheName:nil) or delete the
cache before the new FRC is created. In your situation, a cache probably does not make
much sense.

How to prevent Core Data fetch request from resetting its predicate when SwiftUI List selection changes?

I tried your project and put in some breakpoints and the problem is when a selection is made, ContentView's body is called, which inits FruitPicker with the default FetchRequest instead of the one with the search predicate.

In looking over your coded I noticed some non-standard things. PersistenceController should be a struct not an ObservableObject (see the default app template with core data checked). The use of computed bindings looks odd to me but cool if it works.

To fix the problem you could break up the search and the list into 2 Views, so that the List is init with the new search term and then the FetchRequest will always be correct, e.g.

struct FruitPickerSearch: View {
@State var searchText = ""

var body: some View {
FruitPicker(searchText: searchText)
.searchable(text: $searchText)
.environment(\.editMode, .constant(EditMode.active))
.navigationTitle("Garden")
}
}

struct FruitPicker: View {
private var fetchRequest: FetchRequest<Fruit>
private var fruits: FetchedResults<Fruit> {
fetchRequest.wrappedValue
}

init(searchText: String){
let predicate = searchText.isEmpty ? nil : NSPredicate(format: "name CONTAINS[cd] %@", searchText)
fetchRequest = FetchRequest(sortDescriptors: [NSSortDescriptor(keyPath: \Fruit.name, ascending: true)],
predicate: predicate,
animation: .default)
}

var body: some View {
List(fruits) { fruit in
Text(fruit.name ?? "")
}
}
}

Predicate in FetchResults for Core Data has no effect

Following up to the two comments above, maybe the answer is in the Apple documentation for NSFetchedResultsController. Read the section Modifying the Fetch Request, noting in particular that

You cannot simply change the fetch request to modify the results.

Core Data NSPredicate deleted == NO does not work as expected

The problem is that you have defined an attribute deleted for your entity. That conflicts with the isDeleted method of NSManagedObject, so you should rename that attribute.

The following "experiment" shows that strange things happen if you call your attribute "deleted" (c is a managed object with a custom deleted attribute):

// Set custom "deleted" property to YES:
c.deleted = @YES;

// Use the property, as your Code 1
NSLog(@"%@", [c deleted]);
// Output: 1

// Use Key-Value Coding, as your Code 2
NSLog(@"%@", [c valueForKey:@"deleted"]);
// Output: 0

// Now really delete the object and try again:
[context deleteObject:c];
NSLog(@"%@", [c valueForKey:@"deleted"]);
// Output: 1

Your "Code 1" refers to the property, therefore it returns the expected result. "Code 2" uses Key-Value Coding, and [c valueForKey:@"deleted"] returns YES if the object
actually has been deleted from the context!

So renaming that attribute should solve your problem. Unfortunately the compiler does not
emit warnings if an attribute name conflicts with a built-in method.

Result of Core Data query does not change when using a predicate to filter

You want to exclude all ChargeStations which have a PlugType.type = "type", or equivalently "include only those ChargeStations where the count of (PlugTypes with type = "type2") is zero". So try:

[NSPredicate predicateWithFormat:@"SUBQUERY(stations, $C, ANY $C.hasPlugType.type = %@).@count = 0",@"type2"];

Is there a way to modify fetched results with a predicate after they are initialized?

Is there a way to modify fetched results with a predicate after they
are initialized?

Well... no, not in the way you try to do this, and even if you'd try to create it with NSFetchRequest instance, which is reference, and allows to change predicate later, that wouldn't work, because SwiftUI's FetchRequest stores copy of provided fetch request (or creates own with provided parameters)... so, no. But...

You can break apart view providing fetch request parameters with view constructing fetch request and showing result.

Here is a demo of approach (important part of it) which gives you possibility to get results with different dynamically changed predicates:

struct MasterView: View {
@State var predicate: NSPredicate? = nil
var body: some View {
VStack {
Button(action: { // button just for demo
self.predicate = NSPredicate(format: "title contains[c] %@", "h")
}, label: { Text("Filter") })
ResultView(predicate: self.predicate)
}
}
}

struct ResultView: View {

@FetchRequest
var events: FetchedResults<Event>

@Environment(\.managedObjectContext)
var viewContext

init(predicate: NSPredicate?) {
let request: NSFetchRequest<Event> = Event.fetchRequest()
request.sortDescriptors = [NSSortDescriptor(keyPath: \Event.timestamp, ascending: true)]
if let predicate = predicate {
request.predicate = predicate
}
_events = FetchRequest<Event>(fetchRequest: request)
}

var body: some View {
List {
ForEach(events, id: \.self) { event in
...

Core Data not updating, updated model

You should not name an Core Data attribute "deleted", that conflicts with the
isDeleted method of NSManagedObject.

Compare https://stackoverflow.com/a/16003894/1187415 for a short analysis of that problem.

There are other attribute names that cause conflicts, e.g. "updated" (compare Cannot use a predicate that compares dates in Magical Record). Unfortunately, there are no warnings at compile time or runtime,
and the documentation on what acceptable attribute names are is also quite vague.

CoreData Fetch Resturns 0 Results on second use of a Predicate

The different behaviour could be caused by the fact that the first fetch request
is executed against objects which are already loaded in the managed object context,
and the second fetch request is translated to a SQLite query.

I am not sure if a Core Data predicate of the form "value IN key" actually works,
so you could replace your predicate with the equivalent:

[NSPredicate predicateWithFormat:@"NOT (ANY games == %@)", self.game]

However,
here seem to be problems with Core Data fetch requests containing "NOT ANY",
so I would try the following one:

[NSPredicate predicateWithFormat:@"SUBQUERY(games, $g, $g == %@).@count == 0",
self.game]


Related Topics



Leave a reply



Submit