Обновление fetchedResultsController для предиката, установленного UISearchBar

Рефакторинг изменен на ванильный UIViewController

Вместо того, чтобы UITableView переключаться между активным и неактивным UISearchController, я провел рефакторинг в ванильный UIViewController с UISearchBar вверху и UITableView прямо под ним.

То, что я пытаюсь сделать, это переключить fetchedResultsController между наличием предиката, который устанавливается текстом в строке поиска, и предикатом, который захватывает все.

Я нашел этот ответ, который описывает решение аналогичной проблемы в Objective-C и послужил основой для рефакторинга моего проекта Swift:

Как отфильтровать NSFetchedResultsController (CoreData) с помощью UISearchDisplayController/UISearchBar https://stackoverflow.com/a/9512891/4475605

Моя проблема: как обновить fetchedResultsController для текста searchBar?

tableView заполняется правильно, но я не могу понять, как обновить fetchedResultsController для моего searchPredicate Вот что я пробовал.

Вот как я объявляю свои NSPredicate и NSFetchedResultsController в верхней части класса:

var searchPredicate = NSPredicate()

// Create fetchedResultsController to store search results
lazy var fetchedResultsController: NSFetchedResultsController = {
    let fetchRequest = NSFetchRequest(entityName: "Song")
    let sortDescriptor = NSSortDescriptor(key: "songDescription", ascending: true);
    // ** THESE TWO LINES CAUSE A CRASH, BUT NO COMPILER ERRORS **
    // let predicate = self.searchPredicate
    // fetchRequest.predicate = predicate
    fetchRequest.sortDescriptors = [sortDescriptor]
    fetchRequest.fetchBatchSize = 20

    let frc = NSFetchedResultsController (fetchRequest: fetchRequest, managedObjectContext: self.managedObjectContext, sectionNameKeyPath: "songDescription", cacheName: nil)

    frc.delegate = self

    return frc
}()

Вот мои UISearchBarDelegate методы:

// MARK: - UISearchBarDelegate methods
// called when text changes (including clear)
internal func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
    print("searchText = \(searchBar.text)")
    searchPredicate = NSPredicate(format: "(songDescription contains [cd] %@) || (songStar contains[cd] %@)", searchBar.text!, searchBar.text!)
    // TODO: figure out how to update fetchedResultsController w/ predicate
}

// called when cancel button pressed
internal func searchBarCancelButtonClicked(searchBar: UISearchBar) {
    searchBar.resignFirstResponder()
    searchBar.text = ""
    // TODO: flip back to normal fetchResultsController
}

Вот мои NSFetchedResultsControllerDelegate методы

internal func controllerWillChangeContent(controller: NSFetchedResultsController) {
    print("controllerWillChangeContent")
    tableView.beginUpdates()
}

internal func controllerDidChangeContent(controller: NSFetchedResultsController) {
    print("controllerDidChangeContent")
    tableView.reloadData()
    tableView.endUpdates()
}

internal func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
    switch type {
    case .Insert:
        tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Automatic)
    case .Delete:
        tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Automatic)
    case .Update:
        tableView.reloadRowsAtIndexPaths([indexPath!], withRowAnimation: .Automatic)
    case .Move:
        tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Automatic)
        tableView.insertRowsAtIndexPaths([indexPath!], withRowAnimation: .Automatic)
    }
}

Спасибо за чтение. Я приветствую ваши предложения.


person Adrian    schedule 29.10.2015    source источник


Ответы (1)


Это не такой уж быстрый псевдокод... он наверняка не скомпилируется ни одним быстрым компилятором.

Ваш FRC не использует кэш, поэтому кэш не подлежит удалению, и мы можем просто назначить предикат существующему запросу выборки FRC.

Возможно, вы не захотите выполнять полную новую выборку при каждом изменении символа в строке поиска, или вы можете захотеть выполнить поиск только по первому символу и использовать подмножества для последующих символов.

// called when text changes (including clear)
internal func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
    var predicate:NSPredicate = nil
    if searchBar.text.length != 0 {
        predicate = NSPredicate(format: "(songDescription contains [cd] %@) || (songStar contains[cd] %@)", searchBar.text!, searchBar.text!)
    }
    fetchedResultsController.fetchRequest.predicate = predicate
    fetchedResultsController.performFetch()
    tableView.reloadData()
}

// called when cancel button pressed
internal func searchBarCancelButtonClicked(searchBar: UISearchBar) {
    searchBar.resignFirstResponder()
    searchBar.text = ""
    fetchedResultsController.fetchRequest.predicate = nil
    fetchedResultsController.performFetch()
    tableView.reloadData()
}
person Jody Hagins    schedule 29.10.2015
comment
Спасибо, что вывел меня на финишную прямую! Я выяснил метод поиска из этого сообщения stackoverflow.com/a/32073151/4475605, но отмена поиска выдавала меня отключили, потому что автозаполнение предлагало `fetchedResultsController.fetchRequest.predicate = NilLiteralConvertible`, когда я пытался ввести nil! Я набрал ноль, и это позаботилось обо всем остальном. - person Adrian; 29.10.2015