swiftnoob
swiftnoob

Reputation: 413

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

Upvotes: 1

Views: 1506

Answers (2)

Joakim Danielson
Joakim Danielson

Reputation: 51882

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)
}

Upvotes: 2

HunterLion
HunterLion

Reputation: 4006

That var must return an array of String, but you are returning the array items, which is an array of type MyBookmark.

Solution: convert the array to a type of [String].

Replace that variable with:

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

Upvotes: 2

Related Questions