带有核心数据的TableViewController中的搜索栏

时间:2017-08-16 16:27:51

标签: swift search swift3 uisearchbar

我正在使用Core Data创建一个TableViewController。实际上,用户可以向表视图添加新项目,这些项目将保存在核心数据中。视图将显示联系人列表。 一切都运行良好,但我找不到搜索栏工作。我尝试了很多,但我是swift的新手,这是我的第一个应用程序。请告诉我应该在代码中添加什么内容?

class ContactsViewController: UITableViewController {

    @IBOutlet var searchBar: UISearchBar!
    var contacts: [NSManagedObject] = []



    override func viewDidLoad() {
        super.viewDidLoad()
        fetch()
        tableView.reloadData()

    }

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

    //MARK: - Data Source

    func fetch() {
        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
        let managedObjectContext = appDelegate.persistentContainer.viewContext
        let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName:"Contact")
        do {
            contacts = try managedObjectContext.fetch(fetchRequest) as! [NSManagedObject]
        } catch let error as NSError {
            print("Could not fetch. \(error)")
        }
    }

    func save(name: String, phoneNumber: String, dataUltimei: String) {
        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
        let managedObjectContext = appDelegate.persistentContainer.viewContext
        guard let entity = NSEntityDescription.entity(forEntityName:"Contact", in: managedObjectContext) else { return }
        let contact = NSManagedObject(entity: entity, insertInto: managedObjectContext)
        contact.setValue(name, forKey: "name")
        contact.setValue(phoneNumber, forKey: "phoneNumber")
        contact.setValue(dataUltimei, forKey: "dataUltimei")
        do {
            try managedObjectContext.save()
            self.contacts.append(contact)
        } catch let error as NSError {
            print("Couldn't save. \(error)")
        }
    }

    func update(indexPath: IndexPath, name:String, phoneNumber: String, dataUltimei: String) {
        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
        let managedObjectContext = appDelegate.persistentContainer.viewContext
        let contact = contacts[indexPath.row]
        contact.setValue(name, forKey:"name")
        contact.setValue(phoneNumber, forKey: "phoneNumber")
        contact.setValue(dataUltimei, forKey: "dataUltimei")
        do {
            try managedObjectContext.save()
            contacts[indexPath.row] = contact
        } catch let error as NSError {
            print("Couldn't update. \(error)")
        }
    }

    func delete(_ contact: NSManagedObject, at indexPath: IndexPath) {
        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
        let managedObjectContext = appDelegate.persistentContainer.viewContext
        managedObjectContext.delete(contact)
        contacts.remove(at: indexPath.row)
    }

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {


        return contacts.count

    }




    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {


        let cell = tableView.dequeueReusableCell(withIdentifier: "ContactCell", for: indexPath)

        var contact = contacts[indexPath.row]

        if isSearching {

            contact = contacts[indexPath.row]

        }
        else {

            contact = contacts[indexPath.row]

        }

        cell.textLabel?.text = contact.value(forKey:"name") as? String

        }
        return cell
    }


    override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
        if editingStyle == .delete {

            do {

                let contact = contacts[indexPath.row]
                delete(contact, at: indexPath)
                fetch()
                tableView.reloadData()


            } catch let error as NSError {
                print("Could not save. \(error), \(error.userInfo)")
            }
        }
    }

    override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        // Return false if you do not want the specified item to be editable.
        return true
    }


    @IBAction func unwindToContactList(segue: UIStoryboardSegue) {
        if let viewController = segue.source as? AddContactViewController {
            guard let name: String = viewController.nameTextField.text, let phoneNumber: String = viewController.phoneNumberTextField.text, let dataUltimei: String = viewController.tabel.text else { return }
            if name != "" && phoneNumber != "" {
                if let indexPath = viewController.indexPathForContact {
                    update(indexPath: indexPath, name: name, phoneNumber: phoneNumber, dataUltimei: dataUltimei)
                } else {
                    save(name:name, phoneNumber:phoneNumber, dataUltimei:dataUltimei)
                }
            }
            tableView.reloadData()
        } else if let viewController = segue.source as? ContactDetailViewController {
            if viewController.isDeleted {
                guard let indexPath: IndexPath = viewController.indexPath else { return }
                let contact = contacts[indexPath.row]
                delete(contact, at: indexPath)
                tableView.reloadData()
            }
        }
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "contactDetailSegue" {
            guard let navViewController = segue.destination as? UINavigationController else { return }
            guard let viewController = navViewController.topViewController as? ContactDetailViewController else { return }
            guard let indexPath = tableView.indexPathForSelectedRow else { return }
            let contact = contacts[indexPath.row]
            viewController.contact = contact
            viewController.indexPath = indexPath
        }
    }

}

2 个答案:

答案 0 :(得分:1)

添加以下功能:

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    if !searchText.isEmpty {
        var predicate: NSPredicate = NSPredicate()
        predicate = NSPredicate(format: "name contains[c] '\(searchText)'")
        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
        let managedObjectContext = appDelegate.persistentContainer.viewContext
        let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName:"Contact")
        fetchRequest.predicate = predicate
        do {
            contacts = try managedObjectContext.fetch(fetchRequest) as! [NSManagedObject]
        } catch let error as NSError {
            print("Could not fetch. \(error)")
        }
    } 
    tableView.reloadData()
}

添加UISearchBarDelegate和UISearchDisplayDelegate,如下所示:

class ViewController: UIViewController, UISearchBarDelegate, UISearchDisplayDelegate 

在viewDidLoad中添加searchBar委托:

searchBar.delegate=self

答案 1 :(得分:1)

要添加到@ViniApp的出色答案

在当今的Swift中,您可能会遇到类似的情况

var searchLetters: String = "" {
    didSet {
        runCoreDataFetchRequest()
        reloadData()
    }
}

因此,只要更改,

override var theFetchRequest: NSFetchRequest<NSFetchRequestResult> {
    let r = NSFetchRequest<NSFetchRequestResult>(entityName: relevantEntityName)

    let s = NSSortDescriptor(key: "id", ascending: false) // for example
    r.sortDescriptors = [s]

    if searchLetters != "" {
        let p = NSPredicate(format: "firstname contains[c] %@", searchLetters)
        r.predicate = p
    }

    return r
}

请注意,以上示例中的“名字”实际上只是您要搜索的实际Core Data实体中的实际字段的名称,因此显然使用实际项目中的实际字段名称,而不是“ firstname” “。

请注意,获取请求是使用searchLetters

构建的

然后,您的核心数据调用的核心将是:

var frc: NSFetchedResultsController<NSFetchRequestResult>!

func runCoreDataFetchRequest() {
    frc = NSFetchedResultsController(
        fetchRequest: theFetchRequest,
        managedObjectContext: core.container.viewContext,
        sectionNameKeyPath: nil,
        cacheName: nil)
    frc.delegate = self

    do {
        try frc.performFetch()
    } catch {
        fatalError("frc fetch fail \(error)")
    }
}

请注意,无论当前值是多少,它都会使用theFetchRequest

因此,简而言之,runCoreDataFetchRequest为您运行performFetch

最后不要忘记,在运行获取后,您只需重新加载表或集合视图:

请注意

var searchLetters: String = "" {
    didSet {
        runCoreDataFetchRequest()
        reloadData()
    }
}

设置searchLetters实际上可以完成整个工作!