斯威夫特使用NSFetchedResultsController和UISearchBarDelegate

问题描述 投票:3回答:2

我找了一个体面的解决这个问题。我想实现一个TableView中,我有一些简单的搜索功能。

我发现无论是在所有的例子使用过时UISearchDisplayController或使用新UISearchController但没有NSFetchedResultsController目前这是使用Core Data / NSFetchedResultsController填充

到目前为止,我已经成功地得到它的一个地步,我可以收集用户的搜索字符串(呜!)。我知道,我可能需要一个单独的FRC执行上进行搜索,但所有尝试上面提到的,现在最多都失败了。

我的类是符合以下协议:

class JobListController: UIViewController, UITableViewDelegate, UITableViewDataSource, NSFetchedResultsControllerDelegate, UISearchBarDelegate{

因为我有依赖于这个类是一个UITableViewController我有我的两个UIViewController现有的功能已经写入负载我不能使用IBOutlets

@IBOutlet var tblJobs : UITableView!
@IBOutlet weak var searchBar: UISearchBar!

和我的空数组来保存我的各种Core Data位和鲍勃:

var workItems = [Work]()
var filteredWorkItems = [Work]()

这里是我正在初始化我FRC,与我一起MOC和我留在我的空第二FRC因为我肯定它会在某个时刻需要:

  let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext

lazy var fetchedResultsController: NSFetchedResultsController = {
    let workFetchRequest = NSFetchRequest(entityName: "Work")
    let primarySortDescriptor = NSSortDescriptor(key: "createdDate", ascending: true)
    let secondarySortDescriptor = NSSortDescriptor(key: "town", ascending: true)
    workFetchRequest.sortDescriptors = [primarySortDescriptor, secondarySortDescriptor]

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

    frc.delegate = self


    return frc
    }()

var searchResultsController: NSFetchedResultsController?

在我viewDidLoad功能我设立代表/数据源为我的表和搜索栏:

  tblJobs.delegate = self
  tblJobs.dataSource = self
  searchBar.delegate = self

这里是searchBar功能这是我最高的地方。该stringMatch变量是从以前的尝试吃剩的,我希望能够通过此不同参数的大量搜索,但如果我能得到的只是一个工作将是一个良好的开端。

func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
    println("Search text is \(searchText)")
    self.filteredWorkItems = self.workItems.filter({( work: Work) -> Bool in
        //
        let stringMatch = work.postcode.rangeOfString(searchText)
        return stringMatch != nil
    })

    if(filteredWorkItems.count == 0){
        searchActive = false;
    } else {
        searchActive = true;
    }
    self.tblJobs.reloadData()
}

这是我cellForRowAtIndexPath函数来显示我是如何从fetchedResultsController拉数据

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
    let cell =  self.tblJobs.dequeueReusableCellWithIdentifier(
        "JobCell", forIndexPath: indexPath)
        as! JobTableViewCell

    let workItem = fetchedResultsController.objectAtIndexPath(indexPath) as! Work



 //...

    return cell
}

所以你可以看到我有一些事情会在这里,最后我想弄清楚我如何用我的新得到searchText查询使用的字符串我FRC,然后将结果在View正确地过滤。

更新:

我试图搜索字符串添加到我的NSPredicate在像这样的FRC

lazy var fetchedResultsController: NSFetchedResultsController = {

   ../


    workFetchRequest.predicate = NSPredicate(format:"title contains[cd] %@", savedSearchTerm!)

   //...
    return frc
    }()

这将导致'JobListController.Type' does not have a member named 'savedSearchTerm'

在我的课上我已经设置它是这样的:

var savedSearchTerm: NSString?

所以,不知道我做错了吗?

ios swift core-data uisearchbar
2个回答
7
投票

从你的代码,我假设你想使用同一个表视图来显示结果。所以,你只需要基于搜索项新的过滤器来更新您的FRC。

存储在一个变量的搜索词。在FRC工厂功能,包括谓词,是这样的:

request.predicate = searchText?.characters.count > 0 ?
 NSPredicate(format:"title contains[cd] %@", searchText!) : nil

当文本改变,复位FRC和重装。

fetchedResultsController = nil
tableView.reloadData()

如果你有额外的过滤器,如范围按钮,添加附加条款谓词。


0
投票

雨燕4.2

这是我的应用程序的一个工作方案。我已经削减下来,使之简单,以显示它是如何工作的。

我有大约6000行中,我通过3个不同范围搜索的数据库:备注,作者和关键词。我打电话initializeFetchedResultsController与默认值viewDidLoad功能。后来当用户开始在搜索栏中键入,开始用所需的值再次调用它。

该提取部分:

let EMPTY_STRING = "" // I don't like string literals in my code so define them as static variables separately

// Giving two default values
func initializeFetchedResultsController(_ text: String: EMPTY_STRING, _ scope: Int = 0) {
    fetchRequest.sortDescriptors = [NSSortDescriptor(key: NotesAttributes.author.rawValue, ascending: true)]
            if searchedStringTemp != EMPTY_STRING { // Whatever conditions you want to pass on
                let p0 = NSPredicate(format: NotesAttributes.scope.rawValue + " != \(scope)")
                let p1 = NSPredicate(format: "\(column) CONTAINS[cd] %@", "\(text)")
                fetchRequest.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [p0, p1])
            }

    fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: AppDelegate().sharedInstance().persistentContainer.viewContext, sectionNameKeyPath: nil, cacheName: nil)
    fetchedResultsController.delegate = self

    do {
        try self.fetchedResultsController.performFetch()
    } catch {
        let fetchError = error as NSError
        print("Error 12312: Unable to Perform Fetch Request")
        print("\(fetchError), \(fetchError.localizedDescription)")
    }
}

搜索控制器:

// MARK: - UISearchBar Delegate
extension AllNotesVC: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
    // This is my function which I call to start search
    notesSearched(searchBar.text!, searchBar.scopeButtonTitles![selectedScope])
}
}

// MARK: - UISearchResultsUpdating Delegate
extension AllNotesVC: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
    let text = searchController.searchBar.text!
    let searchBar = searchController.searchBar
    let scope = searchBar.scopeButtonTitles![searchBar.selectedScopeButtonIndex]
    // This is my function which I call to start search
    notesSearched(text, scope)
}
}

而这其中,我notesSearched方法重新初始化读取结果控制器和每次重新加载表。

// MARK: - Private instance methods

private func notesSearched(_ text: String, _ scope: Int) {
    initializeFetchedResultsController(text, scope)
    tableView.reloadData()
}

同时呼吁做这么多表重载可能无法做到这一点的最有效的方式,但它闪电快,因为这将更新表格实时为用户键入它提供了一个极好的用户体验。

© www.soinside.com 2019 - 2024. All rights reserved.