通过UISearchBar设置的谓词更新fetchedResultsController

5

重构为普通的UIViewController

与其让UITableView在活动和非活动的UISearchController之间切换,我将其重构为一个带有顶部UISearchBar和直接位于其下方的UITableView的普通UIViewController

我想做的是在fetchedResultsController之间切换谓词,这个谓词由搜索栏中的文本设置,并且抓取所有内容。

我发现了这个答案,它描述了Objective-C中类似问题的解决方案,并成为我重构Swift项目的基础:

如何使用UISearchDisplayController / UISearchBar过滤NSFetchedResultsController(CoreData) https://dev59.com/wW855IYBdhLWcg3wNhd1#9512891

我的问题:如何为searchBar文本更新我的fetchedResultsController?

tableView正确地填充,但我无法弄清楚如何更新我的fetchedResultsController以匹配我的searchPredicate。这是我尝试过的方法。

以下是我在类顶部声明NSPredicateNSFetchedResultsController的方式:

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

感谢您的阅读。我欢迎您的建议。
1个回答

22

这是一个不太流畅的伪代码...它肯定无法在任何Swift编译器中编译。

您的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()
}

谢谢你帮我完成了这个项目!我从这篇文章 https://dev59.com/B47da4cB1Zd3GeqP-DVq#32073151 中找到了搜索的方法,但是取消搜索时会出现问题,因为自动完成会建议 fetchedResultsController.fetchRequest.predicate = NilLiteralConvertible,而我想输入的是 nil!最后我输入了 nil,问题得以解决。 - Adrian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接