使用 Swift 在带有 Coredata 的表格视图中搜索栏和显示?

Posted

技术标签:

【中文标题】使用 Swift 在带有 Coredata 的表格视图中搜索栏和显示?【英文标题】:SearchBar & Display in table view with Coredata using Swift? 【发布时间】:2016-01-26 22:07:57 【问题描述】:

我是 ios 开发的新手,正在使用 Swift 开发我的第二个应用程序。我无法在我的表格视图控制器中合并 SearchBar 和显示搜索。

我的应用中有 2 个视图。 First View 生成一个水果数组。第一视图的输出:[苹果、橙子、香蕉、梨]。然后是【石榴、梨、西瓜、香瓜】等等。一次一个数组。

每个水果数组都使用 NSFetchedResultsController 存储在核心数据中,以显示在 tableviewcontroller 中。 我的 Coredata 布局:

import UIKit
import CoreData

@objc(Fruits)

class Fruits: NSManagedObject 
    @NSManaged var date: String
    @NSManaged var fruit: String

My Second View 显示水果列表。现在我在表格视图的顶部添加了一个搜索栏和显示。但我无法让它发挥作用。

使用的协议:

class HistoryTableViewController: UITableViewController, NSFetchedResultsControllerDelegate

声明的变量:

let managedObjectContext: NSManagedObjectContext? = (UIApplication.sharedApplication().delegate as? AppDelegate)?.managedObjectContext
var fetchedResultsController: NSFetchedResultsController?
var fetchRequest = NSFetchRequest(entityName: "Fruits")

我班有两个出口:

@IBOutlet weak var searchBar: UISearchBar! // the Search Bar & Display
@IBOutlet var tblHistory: UITableView! = nil // Table View

表格视图的数据填充:

override func numberOfSectionsInTableView(tableView: UITableView) -> Int 
        return fetchedResultsController?.sections?.count ?? 0
    
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
       
        return fetchedResultsController?.sections?[section].numberOfObjects ?? 0
    

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: (NSIndexPath!)) -> UITableViewCell
    
        let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as UITableViewCell
            if let cellFruit = fetchedResultsController?.objectAtIndexPath(indexPath) as? Fruits
            
                cell.textLabel?.text = cellFruit.fruit
                cell.detailTextLabel?.text = cellFruit.date
            
            return cell
    

    // Override to support conditional editing of the table view.
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool 
        // Return false if you do not want the specified item to be editable.
        return true
    

    //MARK: NSFetchedResultsController Delegate Functions
func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) 

        switch type 
        case NSFetchedResultsChangeType.Insert:
            tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: UITableViewRowAnimation.Fade)
            break
        case NSFetchedResultsChangeType.Delete:
            tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: UITableViewRowAnimation.Fade)
            break
        case NSFetchedResultsChangeType.Move:
            break
        case NSFetchedResultsChangeType.Update:
            break
        default:
            break
        
    

override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) 
            //Delete object from entity, remove from list
            if editingStyle == .Delete 
            
            switch editingStyle 
            case .Delete:
managedObjectContext?.deleteObject(fetchedResultsController?.objectAtIndexPath(indexPath) as! Fruits)
                do 
                    try managedObjectContext?.save()
                catch
                print("Fruit set deleted successfully.")
            case .Insert:
                break
            case .None:
                break
            
        
func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) 

        switch type 
        case NSFetchedResultsChangeType.Insert:
            tableView.insertRowsAtIndexPaths(NSArray(object: newIndexPath!) as! [NSIndexPath], withRowAnimation: UITableViewRowAnimation.Fade)
            break
        case NSFetchedResultsChangeType.Delete:
            tableView.deleteRowsAtIndexPaths(NSArray(object: indexPath!) as! [NSIndexPath], withRowAnimation: UITableViewRowAnimation.Fade)
            break
        case NSFetchedResultsChangeType.Move:
            tableView.deleteRowsAtIndexPaths(NSArray(object: indexPath!) as! [NSIndexPath], withRowAnimation: UITableViewRowAnimation.Fade)
            tableView.insertRowsAtIndexPaths(NSArray(object: newIndexPath!) as! [NSIndexPath], withRowAnimation: UITableViewRowAnimation.Fade)
            break
        case NSFetchedResultsChangeType.Update:
            tableView.cellForRowAtIndexPath(indexPath!)
            break
        default:
            break
        
    

    func controllerWillChangeContent(controller: NSFetchedResultsController) 
        tableView.beginUpdates()
    

    func controllerDidChangeContent(controller: NSFetchedResultsController) 
        tableView.endUpdates()
    

如何从 coredata 中搜索任何水果并过滤视图? Swift 编码中的搜索栏和显示功能应该使用哪个委托函数?

任何关于我可能在这里遗漏的概念的帮助将不胜感激!谢谢。

更新: 正如 Daniel Eggert 建议的那样,我正在尝试将谓词用于搜索控制器功能,但谓词总是给出 nil。我错过了什么???

类中声明的变量:

var results: NSArray = []
var searchPredicate: NSPredicate?
var searchController: UISearchController!

谓词函数:

//Search Functionality
        func updateSearchResultsForSearchController(searchController: UISearchController)
        
            let searchText = self.searchController?.searchBar.text
            if let searchText = searchText 
                searchPredicate = NSPredicate(format: "fruit contains[cd] %@", searchText)
                results = (self.fetchedResultsController!.fetchedObjects?.filter() 
                    return self.searchPredicate!.evaluateWithObject($0)
                     as! [Fruits]?)!
            self.tableView.reloadData()
            
        

    // Called when text changes (including clear)
    func searchBar(searchBar: UISearchBar, textDidChange searchText: String)
    
        if !searchText.isEmpty
        
            var predicate: NSPredicate = NSPredicate()
            predicate = NSPredicate(format: "fruit contains [cd] %@", searchText)
            let sortDescriptor = NSSortDescriptor(key: "date", ascending: true)
            fetchRequest.sortDescriptors = [sortDescriptor]
            fetchedResultsController?.fetchRequest.predicate? = predicate
            print(fetchedResultsController?.fetchRequest.predicate) // this is always nil. Why????????????
            do 
                try fetchedResultsController?.performFetch()
            catch
            print("results array: \(results)") // this array should have values of the table view, but is empty. Why ?????????????????
            fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managedObjectContext!,
                sectionNameKeyPath: "fruit", cacheName: nil)
            fetchedResultsController?.delegate = self
            tableView.reloadData() 
        
    

【问题讨论】:

如果搜索栏文字长度为0,如何处理? 【参考方案1】:

您想在获取的结果控制器上设置谓词。

在获取结果控制器上更改获取请求后,您需要调用performFetch() 让它重新获取其数据。然后在表格视图上调用reloadData()

但是,由于语言、区域设置和 Unicode 之间的交互方式,对重要示例的文本搜索可能会很棘手。我会推荐我书中的文本一章:https://www.objc.io/books/core-data/

【讨论】:

丹尼尔请建议我采取的方法是否正确。购买后即可访问您书中的文本章节。 漂亮的书,已购买,我很喜欢。最后是一些深入的 Swift/iOS 示例和实用方法。 10/10 会推荐【参考方案2】:

如果要实现可搜索的tableView?您必须使用UISearchResultsUpdating 协议方法而不是称为searchBar:textDidChangeUISearchBarDelegate 协议方法。当UISearchResultsUpdating 协议方法不可用时,您可以使用searchBar:textDidChange 方法!这两个类都是有用且强大的。并且易于实施

【讨论】:

以上是关于使用 Swift 在带有 Coredata 的表格视图中搜索栏和显示?的主要内容,如果未能解决你的问题,请参考以下文章

Swift CoreData:无法使用带有自定义功能的 sectionNameKeyPath 对 tableView 进行分区

Swift:表格单元格未正确设置按钮

在 Swift 中使用 Core Data 在表格视图的部分中显示数据

带有 Swift 和 iOS 8+ 的 CoreData 仍然需要 willAccessValueForKey() 吗?

在 Swift 中使用 RestKit 和 CoreData

Swift/IOS/CoreData:如何在自动生成的 CoreData 类中将 var 定义为枚举类型?