2

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

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

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

Я нашел ответ, который описывает решение аналогичной задачи в 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) 
    } 
} 

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

ответ

15

Это не так-быстрый псевдо-код ... он, безусловно, не будет компилироваться с помощью любого быстрого компилятора.

Ваш 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() 
} 
+0

Благодарим за то, что вышли на финишную прямую! Я понял метод поиска из этого сообщения http://stackoverflow.com/a/32073151/4475605, но отмена поиска меня отбрасывала с автозаполнения b/c, предлагая 'fetchedResultsController.fetchRequest.predicate = NilLiteralConvertible', когда я был пытаясь напечатать 'nil'! Я набрал нуль, и это позаботилось обо всем остальном. – Adrian

Смежные вопросы