没有使用NSArray,但得到“致命错误:NSArray元素无法匹配Swift数组元素类型”

时间:2016-08-26 20:53:47

标签: ios arrays swift filter nsarray

我在Xcode 8 beta 6中使用Swift 3,目标是iOS 10.0。我在UISearchController中实施了一个简单的UITableView支持NSFetchedResultsController.我有两个属性

var patients = [Patient]() // Assigned to fetchedResultsController.fetchedObjects when the fetch is performed, and when the moc is updated.
var searchResults = [Patient]()

在我的updateSearchResults(for searchController: UISearchController)方法中,我这样做:

func updateSearchResults(for searchController: UISearchController) {
    if let searchText = searchController.searchBar.text {
        self.searchResults = people.filter {
        return $0.lastName!.localizedCaseInsensitiveContains(searchText)
    }

使用断点,我已经确定代码到达filter方法,但没有输入,失败了:

  

致命错误:NSArray元素无法匹配Swift数组元素类型

我已经看过一堆涉及此错误的其他SO问题,但没有一个有帮助。我也尝试在people方法中明确地投射updateSearchResults,但没有运气。想法?

UPDATE tableViewController和Patient子类的完整代码:

import UIKit
import CoreData

class PatientsListViewController: UITableViewController, NSFetchedResultsControllerDelegate, UISearchResultsUpdating {

    enum SegueIdentifier: String {
        case showPatientDetail
    }
    //MARK: Properties
    var managedObjectContext: NSManagedObjectContext!
    var fetchedResultController: NSFetchedResultsController<Patient>!
    var searchController: UISearchController!

    var searchResults: [Patient] = []
    var patients: [Patient] = []

    override func viewDidLoad() {
        super.viewDidLoad()

        let fetchRequest: NSFetchRequest<Patient> = Patient.fetchRequest()
        let sortDescriptor = NSSortDescriptor(key: "lastName", ascending: true)
        fetchRequest.sortDescriptors = [sortDescriptor]

        fetchedResultController = NSFetchedResultsController<Patient>(fetchRequest: fetchRequest, managedObjectContext: managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
        fetchedResultController.delegate = self

        do{
            try fetchedResultController.performFetch()
            patients = fetchedResultController.fetchedObjects!
        }catch{
            print(error)
        }

        //Add Search bar to the table header
        searchController = UISearchController(searchResultsController: nil)
        tableView.tableHeaderView = searchController.searchBar
        searchController.searchResultsUpdater = self
        searchController.dimsBackgroundDuringPresentation = false
    }

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

    // MARK: - Table view data source

    override func numberOfSections(in tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        guard let numberOfSections = fetchedResultController.sections?.count else {
            return 0
        }
        return numberOfSections
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        //        let section = fetchedResultController.sections![section]
        //        let numberOfRows = section.numberOfObjects
        if searchController.isActive {
            return searchResults.count
        } else {
            return fetchedResultController.sections![section].numberOfObjects
        }

    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: PatientCell.reuseIdentifier, for: indexPath) as! PatientCell
        let patient = (searchController.isActive) ? searchResults[indexPath.row] : fetchedResultController.object(at: indexPath)
        cell.configure(with: patient)

        return cell
    }

    override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        if searchController.isActive{
            return false
        }else{
            return true
        }
    }

    override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
        let deleteAction = UITableViewRowAction(style: .destructive, title: "Delete") { (action, indexPath) -> Void in
            let patientToDelete = self.fetchedResultController.object(at: indexPath)
            self.managedObjectContext.delete(patientToDelete)

            do{
                try self.managedObjectContext.save()
            }catch{
                print(error)
            }

        }
        return [deleteAction]
    }



    // MARK: - FetchedResultsController delegate

    // Notify the tableView that updates will begin
    func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
        tableView.beginUpdates()
    }

    //Cover all cases of row changes like move, delete, insert, update
    func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
        switch  type{
        case .insert:
            if let newIndexPath = newIndexPath{
                tableView.insertRows(at: [newIndexPath], with: .fade)
            }
        case .delete:
            if let indexPath = indexPath{
                tableView.deleteRows(at: [indexPath], with: .fade)
            }
        case .update:
            if let indexPath = indexPath{
                tableView.reloadRows(at: [indexPath], with: .fade)
            }
        case .move:
            break
        }

        patients = controller.fetchedObjects as! [Patient]
    }

    // Notify the tableView that updates are done
    func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
        tableView.endUpdates()
    }

    //Pass Patient to PatientDetailViewController
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        guard let identifier = segue.identifier.flatMap(SegueIdentifier.init) else { return }

        switch identifier {
        case .showPatientDetail:
            guard let indexPath = tableView.indexPathForSelectedRow else {
                fatalError("No row selected in tableView")
            }
            let destinationController = segue.destination as! PatientDetailViewController
            destinationController.patient = (searchController.isActive) ? searchResults[indexPath.row] : fetchedResultController.object(at: indexPath)
        }
    }

    //Implement Search Bar

    func filterContent(for searchText:String) {
        searchResults = patients.filter( { patient -> Bool in
            let nameMatch = patient.lastName?.localizedCaseInsensitiveContains(searchText)
            return nameMatch != nil
        })
    }

    func updateSearchResults(for searchController: UISearchController) {
        if let searchText = searchController.searchBar.text {
            filterContent(for: searchText)
            tableView.reloadData()
        }
    }

}

PATIENT:

@objc(Patient)
public class Patient: NSManagedObject {


}


extension Patient {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<Patient> {
        return NSFetchRequest<Patient>(entityName: "Patient");
    }

    @NSManaged public var address: String?
    @NSManaged public var dateOfBirth: String?
    @NSManaged public var firstName: String?
    @NSManaged public var gender: String?
    @NSManaged public var lastName: String?

}

0 个答案:

没有答案