Search code examples
swiftcore-dataswiftui

Cannot convert return expression of type 'FetchedResults<>' to return type '[String]'


I'm trying to search through a list of bookmarks by name stored in Core Data but I'm getting this error next to 'return items' in var searchResults

"Cannot convert return expression of type 'FetchedResults <MyBookmark to return type '[String]'"

 @FetchRequest(sortDescriptors: [NSSortDescriptor(keyPath: \MyBookmark.name, ascending: true)], animation: .default)
 private var items: FetchedResults<MyBookmark>
 @State private var searchText = ""

         ForEach(searchResults, id: \.self) { myBookmark in                        
                    Text(myBookmark.name!)
                    Text(myBookmark.url!)
                   }
                   .searchable(text: $searchText)




         var searchResults: [String] {
            if searchText.isEmpty {
               return items
          } else {
              return items.filter { $0.localizedCaseInsensitiveContains(searchText) }
            }
         }

MyBookmark

@objc(MyBookmark)
public class MyBookmark: NSManagedObject, BaseModel {
    static var all: NSFetchRequest<MyBookmark> {
        let request: NSFetchRequest<MyBookmark> = MyBookmark.fetchRequest()
        request.sortDescriptors = []
        return request
    }
    
}


extension MyBookmark {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<MyBookmark> {
        return NSFetchRequest<MyBookmark>(entityName: "MyBookmark")
    }

    @NSManaged public var name: String?
    @NSManaged public var url: String?

}

extension MyBookmark : Identifiable {

}

This is for a macOS app


Solution

  • You need to execute your fetch request again when the search filter changes. To do that you need to set the predicate of the fetch request.

    Add a new property to handle this

    var query: Binding<String> {
        Binding {
            searchText
        } set: { newValue in
            searchText = newValue
            if newValue.isEmpty {
                items.nsPredicate = NSPredicate(value: true)
            } else {
                items.nsPredicate = NSPredicate(format: "name CONTAINS[cd] %@", newValue)            }
        }
    }
    

    And then use the .searchable modifier together with this property

    var body: some View {
        ForEach {
            //...
        }
        .searchable(text: query)
    }