0

I'm trying to filter Core Data by changing the predicate when typing in the search bar, but doing so causes the app to freeze. At first I thought that the problem was in the search bar, but after several tests I realized that when changing the predicate the application freezes.

To try to illustrate what happens: you start typing in the bar and the results are displayed, they change as you type, which is correct. When tapping "Cancel" next to the bar, it sometimes works fine, the results are displayed as expected but most of the time the app to freeze.

If the predicate is exactly the same, the app does NOT freeze, it works fine, but it's not the case.

This is the code causing the problem:

.searchable(text: $searchText)
.onChange(of: searchText) { searchText in
    if !searchText.isEmpty  {
        data.nsPredicate = NSPredicate(format: "business == %@ && title CONTAINS[cd] %@" , business, searchText)
    } else {
        data.nsPredicate = NSPredicate(format: "business == %@", business)
    }
}

This code, while somewhat silly, demonstrates that if I don't change the predicate the problem doesn't show up.

.searchable(text: $searchText)
.onChange(of: searchText) { searchText in
    if !searchText.isEmpty  {
        data.nsPredicate = NSPredicate(format: "business == %@ && title CONTAINS[cd] %@" , business, searchText)
    } else {
        data.nsPredicate = NSPredicate(format: "business == %@ && title CONTAINS[cd] %@" , business, searchText)
    }
}

When freezing occurs, no error is displayed, just freezes, it happens on the simulator and on a real device.

Any ideas? Thanks!

Working code:

Finally got a solution as commented by lorem ipsum.

@State private var searchText = ""
var query: Binding<String> {
    Binding {
        searchText
    } set: { newValue in
        searchText = newValue
        datos.nsPredicate = newValue.isEmpty
        ? NSPredicate(format: "business == %@", business)
        : NSPredicate(format: "business == %@ && title CONTAINS[cd] %@" , business, newValue)
    }
}

var body: some View {

..........
..........

  .searchable(text: query)

}

Source: Apple's setup

Nicoli
  • 643
  • 1
  • 7
  • 23
  • Core Data isn't made to have multiple fetch requests like that. [Core Data Programming Guide: Performance](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/Performance.html). You better option would be to retrieve all your managed objects, and then filter them in your view. – Yrb Mar 01 '22 at 19:19
  • 1
    Use [Apple's setup](https://developer.apple.com/wwdc21/10017) with a custom `Binding`, `onChange` can be a little jumpy. It is around minute 22 – lorem ipsum Mar 02 '22 at 01:30

1 Answers1

0

You need to remove the onChange and pass the search text into your View that creates the FetchRequest, e.g.

SearchView(searchText)
private var fetchRequest: FetchRequest<Item>
private var items: FetchedResults<Item> {
    fetchRequest.wrappedValue
}

init(_ searchText: String) {
    fetchRequest = FetchRequest( // supply a NSPredicate using searchText
}
malhal
  • 26,330
  • 7
  • 115
  • 133