UISearchController returns 只有第一个结果,但 Core Data 有几个结果

UISearchController returns only first results but Core Data has several results

我有 UISearchController,它 returns 只有第一个结果,但 Core Data 有几个结果。

我做了很多不同的变体,但它们对我没有帮助。

否则 UISearchController returns 不正确的结果。

import UIKit
import Foundation
import CoreData

class SongTableVC: UITableViewController, UITableViewDataSource, UITableViewDelegate, NSFetchedResultsControllerDelegate, UISearchControllerDelegate, UISearchBarDelegate, UISearchResultsUpdating {

    // MARK: - var and let
    var appDel = (UIApplication.sharedApplication().delegate as! AppDelegate)
    var context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext!


    // MARK: - NSFetchedResultsController and its functions
    var fetchedResultsController: NSFetchedResultsController!

    func returnRequest() -> NSFetchRequest {
        var fetchRequest = NSFetchRequest(entityName: "Song")
        var sort = NSSortDescriptor(key: "songName", ascending: false)
        fetchRequest.fetchBatchSize = 50
        fetchRequest.predicate = nil
        fetchRequest.sortDescriptors = [sort]
        return fetchRequest
    }

    // MARK: - UISearchController and its fucntions
    var searchController: UISearchController!
    var searchPredicate: NSPredicate!
    var dataFiltered: [Song]? = nil

    func updateSearchResultsForSearchController(searchController: UISearchController) {
        var searchText = searchController.searchBar.text
        searchPredicate = NSPredicate(format: "songName contains[c] %@", searchText)
        dataFiltered = self.fetchedResultsController?.fetchedObjects?.filter(){
            return self.searchPredicate!.evaluateWithObject([=11=])
        } as! [Song]?
        self.tableView.reloadData()
        println(searchPredicate)
    }

    func searchBar(searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
        updateSearchResultsForSearchController(searchController)
    }

    func didDismissSearchController(searchController: UISearchController) {
        searchPredicate = nil
        dataFiltered = nil
        self.tableView.reloadData()
    }



    override func viewDidLoad() {
        super.viewDidLoad()
        self.navigationItem.leftBarButtonItem = self.editButtonItem()

        fetchedResultsController = NSFetchedResultsController(fetchRequest: returnRequest(), managedObjectContext: context, sectionNameKeyPath: "songName", cacheName: "songName")
        fetchedResultsController.delegate = self
        fetchedResultsController.performFetch(nil)

        searchController = ({
            var controllerSearch = UISearchController(searchResultsController: nil)
            controllerSearch.delegate = self
            controllerSearch.searchBar.delegate = self
            controllerSearch.searchBar.sizeToFit()
            controllerSearch.definesPresentationContext = false // default false
            controllerSearch.hidesNavigationBarDuringPresentation = true
            controllerSearch.searchResultsUpdater = self
            controllerSearch.dimsBackgroundDuringPresentation = false 
            self.tableView.tableHeaderView = controllerSearch.searchBar
            return controllerSearch
        })()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    // MARK: - Table view data source

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        // #warning Potentially incomplete method implementation.
        // Return the number of sections.
        if searchPredicate == nil {
            return fetchedResultsController?.sections?.count ?? 0
        } else {
            return 1 ?? 0
        }
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if searchPredicate == nil {
            return fetchedResultsController?.sections?[section].numberOfObjects ?? 0
        } else {
            return dataFiltered?.count ?? 0
        }
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("songID", forIndexPath: indexPath) as! UITableViewCell

        if searchPredicate == nil {
            if var dataForCell = fetchedResultsController.objectAtIndexPath(indexPath) as? Song {
                cell.textLabel?.text = dataForCell.songName
                cell.detailTextLabel?.text = dataForCell.songName
            } else {
                if var dataFilterForCell = dataFiltered?[indexPath.row] {
                    cell.textLabel?.text = dataFilterForCell.songName
                    cell.textLabel?.text = dataFilterForCell.songName
                }
            }
        }
        return cell
    }


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

    // Override to support editing the table view.
    override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
        if editingStyle == .Delete {
            context.deleteObject(fetchedResultsController.objectAtIndexPath(indexPath) as! NSManagedObject)
            context.save(nil)
        } else if editingStyle == .Insert {
            context.insertObject(fetchedResultsController.objectAtIndexPath(indexPath) as! NSManagedObject)
            context.save(nil)
        }    
    }

    func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {
        var tableView = UITableView()
        if searchPredicate == nil {
            tableView = self.tableView
        } else {
            tableView = (searchController.searchResultsController as! SongTableVC).tableView
        }

        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:
            tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: UITableViewRowAnimation.Fade)
            tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: UITableViewRowAnimation.Fade)
            break
        case NSFetchedResultsChangeType.Update:
            break
        default: break
        }
    }

    func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
        var tableView = UITableView()
        if searchPredicate == nil {
            tableView = self.tableView
        } else {
            tableView = (searchController.searchResultsController as! SongTableVC).tableView
        }

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

    func controllerWillChangeContent(controller: NSFetchedResultsController) {
        if searchPredicate == nil {
            tableView.beginUpdates()
        } else {
           (searchController.searchResultsController as? SongTableVC)?.tableView.beginUpdates()
        }
    }

    func controllerDidChangeContent(controller: NSFetchedResultsController) {
        if searchPredicate == nil {
            tableView.endUpdates()
        } else {
            (searchController.searchResultsController as? SongTableVC)?.tableView.endUpdates()
        }
    }

    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "add" {
            searchController.active == false

        }
    }

}

我找到了问题的解决方案

import UIKit
import Foundation
import CoreData

class SongTableViewController: UITableViewController, UITableViewDataSource, UITableViewDelegate, NSFetchedResultsControllerDelegate, UISearchControllerDelegate, UISearchBarDelegate, UISearchResultsUpdating {

    // MARK: - var and lets
    var appDel = (UIApplication.sharedApplication().delegate as! AppDelegate)
    var context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext!

    override func viewDidLoad() {
        super.viewDidLoad()
        fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest(), managedObjectContext: context, sectionNameKeyPath: "nameSong", cacheName: "nameSong")
        fetchedResultsController.delegate = self
        fetchedResultsController.performFetch(nil)

        self.navigationItem.leftBarButtonItem = self.editButtonItem()

        searchController = ({
            var controllerSearch = UISearchController(searchResultsController: nil)
            controllerSearch.delegate = self
            controllerSearch.searchBar.delegate = self
            controllerSearch.hidesNavigationBarDuringPresentation = true
            controllerSearch.definesPresentationContext = false
            controllerSearch.dimsBackgroundDuringPresentation = false
            controllerSearch.searchBar.sizeToFit()
            controllerSearch.searchResultsUpdater = self
            self.tableView.tableHeaderView = controllerSearch.searchBar
            return controllerSearch
        })()

        // 
        println(path)
    }

    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        searchPredicate = nil
        filteredData = nil
        self.tableView.reloadData()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    // MARK: - NSFetchedResultsController and its functions
    var fetchedResultsController: NSFetchedResultsController!

    func fetchRequest() -> NSFetchRequest {
        var fetchRequest = NSFetchRequest(entityName: "Song")
        var sort = NSSortDescriptor(key: "nameSong", ascending: false)
        fetchRequest.fetchBatchSize = 50
        fetchRequest.predicate = nil
        fetchRequest.sortDescriptors = [sort]
        return fetchRequest
    }

    // MARK: - UISearchController and its functions
    var searchController: UISearchController!
    var searchPredicate: NSPredicate!
    var filteredData: [Song]? = nil

    func updateSearchResultsForSearchController(searchController: UISearchController) {
        var searchText = searchController.searchBar.text
        if searchText != nil {
            searchPredicate = NSPredicate(format: "nameSong contains[c] %@", searchText)
            filteredData = fetchedResultsController.fetchedObjects!.filter() {
                return self.searchPredicate.evaluateWithObject([=10=])
            } as? [Song]
            self.tableView.reloadData()
        }
    }

    func searchBar(searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
        updateSearchResultsForSearchController(searchController)
    }

    func didDismissSearchController(searchController: UISearchController) {
        searchPredicate = nil
        filteredData = nil
        self.tableView.reloadData()
    }

    // MARK: - Files from shared folder

    var fileManager = NSFileManager.defaultManager()


    var path = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)



    // MARK: - Table view data source

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        if searchPredicate == nil {
            return fetchedResultsController?.sections?.count ?? 0
        } else {
            return 1 ?? 0
        }
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if searchPredicate == nil {
            return fetchedResultsController?.sections?[section].numberOfObjects ?? 0
        } else {
            return filteredData?.count ?? 0
        }
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("songID", forIndexPath: indexPath) as! UITableViewCell

        if searchPredicate == nil {
            if var dataForCell = fetchedResultsController?.objectAtIndexPath(indexPath) as? Song {
                cell.textLabel?.text = dataForCell.nameSong
            }
        } else {
            if var filteredSearch = filteredData?[indexPath.row] {
                cell.textLabel?.text = filteredSearch.nameSong
            }
        }

        return cell
    }

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

    // Override to support editing the table view.
    override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
        if editingStyle == .Delete {
            context.deleteObject(fetchedResultsController.objectAtIndexPath(indexPath) as! NSManagedObject)
            context.save(nil)
        } else if editingStyle == .Insert {
            context.insertObject(fetchedResultsController.objectAtIndexPath(indexPath) as! NSManagedObject)
            context.save(nil)
        }    
    }

    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:
            tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: UITableViewRowAnimation.Fade)
            tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: UITableViewRowAnimation.Fade)
            break
        case NSFetchedResultsChangeType.Update:
            break
        default: break

        }
    }

    func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
        switch type {
        case NSFetchedResultsChangeType.Insert:
            tableView.insertRowsAtIndexPaths([AnyObject](), withRowAnimation: UITableViewRowAnimation.Fade)
            break
        case NSFetchedResultsChangeType.Delete:
            tableView.deleteRowsAtIndexPaths(NSArray(object: indexPath!) as [AnyObject], withRowAnimation: UITableViewRowAnimation.Fade)
            break
        case NSFetchedResultsChangeType.Move:
            tableView.deleteRowsAtIndexPaths(NSArray(object: indexPath!) as [AnyObject], withRowAnimation: UITableViewRowAnimation.Fade)
            tableView.insertRowsAtIndexPaths(NSArray(object: indexPath!) as [AnyObject], withRowAnimation: UITableViewRowAnimation.Fade)
            break
        case NSFetchedResultsChangeType.Update:
            tableView.cellForRowAtIndexPath(indexPath!)
            break
        default: break
        }
    }

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

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

    /*
    // Override to support rearranging the table view.
    override func tableView(tableView: UITableView, moveRowAtIndexPath fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {

    }
    */

    // Override to support conditional rearranging of the table view.
    override func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool {
        // Return NO if you do not want the item to be re-orderable.
        return true
    }

    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        // Get the new view controller using [segue destinationViewController].
        // Pass the selected object to the new view controller.
    }
    */

}