如何过滤在 Core Data 中有对象的表视图?
How can I filter my tableview that has objects in Core Data?
我正在创建一个联系人应用程序,到目前为止,我已经成功地将项目保存到我的表格视图中。我有一个搜索栏,我想按名字过滤掉我的单元格,我知道因为我在核心数据中工作,所以我必须使用 fetchResultsController 和 NSPredicate。我无法完全弄清楚这些东西,也许有人可以帮助我吗?
这里还有我的核心数据实体,以防万一。
实体:联系人
属性:
- 名字,字符串
- 姓氏,字符串
- 出生日期,字符串
- 电话号码,字符串
- 邮政编码,字符串
我知道有些代码可能不完整,但我只需要知道在哪里使用它的方向。我只想让用户输入一个名字,它会按名字过滤单元格。如果您需要更多信息,请告诉我。
现在这是我的 ContactsTableVC 中的代码:
import UIKit
import CoreData
class ContactsTableVC: UITableViewController, UISearchBarDelegate, NSFetchedResultsControllerDelegate {
@IBOutlet weak var searchBar: UISearchBar!
var isFiltered: Bool = false
//Holds the core data model
var persons: [Person] = []
override func viewDidLoad() {
super.viewDidLoad()
searchBar.delegate = self
self.tableView.separatorStyle = UITableViewCellSeparatorStyle.none
self.tableView.backgroundColor = UIColor(red: 240/255.0, green: 240/255.0, blue: 240/255.0, alpha: 1.0)
fetch()
self.tableView.reloadData()
}
func getContext () -> NSManagedObjectContext {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
return appDelegate.persistentContainer.viewContext
}
// MARK: - Searchbar
//add fetchrequest to did ebgin editing
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
}
func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
if(searchBar.text == "") {
isFiltered = false
} else {
isFiltered = true
}
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
filter(text: searchText)
}
// MARK: - Fetchresults controller / filtering data
func filter(text: String) {
//Create fetch request
let fetchRequest = NSFetchRequest<Person>()
// guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return } replaced with getcontext
// let managedObjectContext = appDelegate.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "Contact", in: getContext())
fetchRequest.entity = entity
let sortDescriptor = NSSortDescriptor(key: "firstName", ascending: false)
let sortDescriptors: [Any] = [sortDescriptor]
fetchRequest.sortDescriptors = sortDescriptors as? [NSSortDescriptor] ?? [NSSortDescriptor]()
if(text.characters.count > 0) {
let predicate = NSPredicate(format: "(firstName CONTAINS[c] %@)", text)
fetchRequest.predicate = predicate
}
let loadedEntities: [Person]? = try? getContext().fetch(fetchRequest)
filteredContacts = [Any](arrayLiteral: loadedEntities) as! [Person]
self.tableView.reloadData()
}
// 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 {
persons = try managedObjectContext.fetch(fetchRequest) as! [Person] //NSManagedObject
} catch let error as NSError {
print("Could not fetch. \(error)")
}
}
func save(firstName: String, lastName: String, dob: String, phoneNumber: String, zipCode: 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 person = NSManagedObject(entity: entity, insertInto: managedObjectContext)
person.setValue(firstName, forKey: "firstName")
person.setValue(lastName, forKey: "lastName")
person.setValue(dob, forKey: "dateOfBirth")
person.setValue(phoneNumber, forKey: "phoneNumber")
person.setValue(zipCode, forKey: "zipCode")
do {
try managedObjectContext.save()
self.persons.append(person as! Person) //previously just contact, no casting!
} catch let error as NSError {
print("Couldn't save. \(error)")
}
}
func update(indexPath: IndexPath, firstName: String, lastName: String, dob: String, phoneNumber: String, zipCode: String) {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedObjectContext = appDelegate.persistentContainer.viewContext
let contact = persons[indexPath.row]
contact.setValue(firstName, forKey: "firstName")
contact.setValue(lastName, forKey: "lastName")
contact.setValue(dob, forKey: "dateOfBirth")
contact.setValue(phoneNumber, forKey: "phoneNumber")
contact.setValue(zipCode, forKey: "zipCode")
do {
try managedObjectContext.save()
persons[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)
persons.remove(at: indexPath.row)
//Always remember to save after deleting, updates Core Data
do {
try managedObjectContext.save()
} catch {
print("Something went wrong \(error.localizedDescription)")
}
}
// MARK: - Table View Setup
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return persons.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ContactCell", for: indexPath) as? PersonsCell
let person = persons[indexPath.row]
cell?.firstName?.text = person.value(forKey:"firstName") as? String
cell?.lastName?.text = person.value(forKey:"lastName") as? String
cell?.dob?.text = person.value(forKey:"dateOfBirth") as? String
cell?.phoneNumber?.text = person.value(forKey:"phoneNumber") as? String
cell?.zipCode?.text = person.value(forKey:"zipCode") as? String
return cell!
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 75
}
// Override to support conditional editing of the table view.
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
// MARK: - Navigation
@IBAction func unwindToContactsList(segue:UIStoryboardSegue) {
if let viewController = segue.source as? AddContactVC {
guard let _firstName: String = viewController.firstNameLbl.text,
let _lastName: String = viewController.lastNameLbl.text,
let _dob: String = viewController.dateOfBirthLbl.text,
let _phoneNumber: String = viewController.phoneNumberLbl.text,
let _zipCode: String = viewController.zipCodeLbl.text
else { return }
if _firstName != "" && _lastName != "" && _dob != "" && _phoneNumber != "" && _zipCode != "" {
if let indexPath = viewController.indexPathForContact {
update(indexPath: indexPath, firstName: _firstName, lastName: _lastName, dob: _dob, phoneNumber: _phoneNumber, zipCode: _zipCode)
print("Any updates?")
} else {
save(firstName: _firstName, lastName: _lastName, dob: _dob, phoneNumber: _phoneNumber, zipCode: _zipCode)
print("added to tableview") //this runs twice for some reason...
}
}
tableView.reloadData()
} else if let viewController = segue.source as? EditContactVC {
if viewController.isDeleted {
guard let indexPath: IndexPath = viewController.indexPath else { return }
let person = persons[indexPath.row]
delete(person, at: indexPath)
tableView.reloadData()
}
}
}
}
您可以使用 NSPredicate 的 sortDescriptors
属性 来过滤您的获取请求的结果。
查看 link 了解更多信息:
How to sort a fetch in Core Data
这是一个示例代码,可以通过 NSFetchedResultsController
实现您的目标。我省略了一些不相关的代码。
class ContactViewController: UITableViewController {
let fetchedResultsController: NSFetchedResultsController<Contact>!
func searchTextFieldDidEditingChanged(_ textField: UITextField) {
let text = textField.text ?? ""
refetch(with: text)
}
// The key is you need change the predicate when searchTextField's
// value changed, and invoke proformFetch() again
func refetch(with text: String) {
let predicate = NSPredicate(format: "firstName CONTAINS %@", text)
fetchedResultsController.fetchRequest.predicate = predicate
do {
try self.fetchedResultsController.performFetch()
tableView.reloadData()
} catch let error as NSError {
loggingPrint("Error: \(error.localizedDescription)")
}
}
}
// MARK: - Table datasource
extension ContactViewController {
override func numberOfSections(in tableView: UITableView) -> Int {
return fetchedResultsController.sections!.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let sectionInfo = fetchedResultsController.sections![section]
return sectionInfo.numberOfObjects
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ContactCell", for: indexPath) as? PersonsCell
let contact = fetchedResultsController.object(at: indexPath)
cell.contact = contact
return cell!
}
}
我正在创建一个联系人应用程序,到目前为止,我已经成功地将项目保存到我的表格视图中。我有一个搜索栏,我想按名字过滤掉我的单元格,我知道因为我在核心数据中工作,所以我必须使用 fetchResultsController 和 NSPredicate。我无法完全弄清楚这些东西,也许有人可以帮助我吗?
这里还有我的核心数据实体,以防万一。
实体:联系人
属性:
- 名字,字符串
- 姓氏,字符串
- 出生日期,字符串
- 电话号码,字符串
- 邮政编码,字符串
我知道有些代码可能不完整,但我只需要知道在哪里使用它的方向。我只想让用户输入一个名字,它会按名字过滤单元格。如果您需要更多信息,请告诉我。
现在这是我的 ContactsTableVC 中的代码:
import UIKit
import CoreData
class ContactsTableVC: UITableViewController, UISearchBarDelegate, NSFetchedResultsControllerDelegate {
@IBOutlet weak var searchBar: UISearchBar!
var isFiltered: Bool = false
//Holds the core data model
var persons: [Person] = []
override func viewDidLoad() {
super.viewDidLoad()
searchBar.delegate = self
self.tableView.separatorStyle = UITableViewCellSeparatorStyle.none
self.tableView.backgroundColor = UIColor(red: 240/255.0, green: 240/255.0, blue: 240/255.0, alpha: 1.0)
fetch()
self.tableView.reloadData()
}
func getContext () -> NSManagedObjectContext {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
return appDelegate.persistentContainer.viewContext
}
// MARK: - Searchbar
//add fetchrequest to did ebgin editing
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
}
func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
if(searchBar.text == "") {
isFiltered = false
} else {
isFiltered = true
}
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
filter(text: searchText)
}
// MARK: - Fetchresults controller / filtering data
func filter(text: String) {
//Create fetch request
let fetchRequest = NSFetchRequest<Person>()
// guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return } replaced with getcontext
// let managedObjectContext = appDelegate.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "Contact", in: getContext())
fetchRequest.entity = entity
let sortDescriptor = NSSortDescriptor(key: "firstName", ascending: false)
let sortDescriptors: [Any] = [sortDescriptor]
fetchRequest.sortDescriptors = sortDescriptors as? [NSSortDescriptor] ?? [NSSortDescriptor]()
if(text.characters.count > 0) {
let predicate = NSPredicate(format: "(firstName CONTAINS[c] %@)", text)
fetchRequest.predicate = predicate
}
let loadedEntities: [Person]? = try? getContext().fetch(fetchRequest)
filteredContacts = [Any](arrayLiteral: loadedEntities) as! [Person]
self.tableView.reloadData()
}
// 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 {
persons = try managedObjectContext.fetch(fetchRequest) as! [Person] //NSManagedObject
} catch let error as NSError {
print("Could not fetch. \(error)")
}
}
func save(firstName: String, lastName: String, dob: String, phoneNumber: String, zipCode: 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 person = NSManagedObject(entity: entity, insertInto: managedObjectContext)
person.setValue(firstName, forKey: "firstName")
person.setValue(lastName, forKey: "lastName")
person.setValue(dob, forKey: "dateOfBirth")
person.setValue(phoneNumber, forKey: "phoneNumber")
person.setValue(zipCode, forKey: "zipCode")
do {
try managedObjectContext.save()
self.persons.append(person as! Person) //previously just contact, no casting!
} catch let error as NSError {
print("Couldn't save. \(error)")
}
}
func update(indexPath: IndexPath, firstName: String, lastName: String, dob: String, phoneNumber: String, zipCode: String) {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedObjectContext = appDelegate.persistentContainer.viewContext
let contact = persons[indexPath.row]
contact.setValue(firstName, forKey: "firstName")
contact.setValue(lastName, forKey: "lastName")
contact.setValue(dob, forKey: "dateOfBirth")
contact.setValue(phoneNumber, forKey: "phoneNumber")
contact.setValue(zipCode, forKey: "zipCode")
do {
try managedObjectContext.save()
persons[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)
persons.remove(at: indexPath.row)
//Always remember to save after deleting, updates Core Data
do {
try managedObjectContext.save()
} catch {
print("Something went wrong \(error.localizedDescription)")
}
}
// MARK: - Table View Setup
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return persons.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ContactCell", for: indexPath) as? PersonsCell
let person = persons[indexPath.row]
cell?.firstName?.text = person.value(forKey:"firstName") as? String
cell?.lastName?.text = person.value(forKey:"lastName") as? String
cell?.dob?.text = person.value(forKey:"dateOfBirth") as? String
cell?.phoneNumber?.text = person.value(forKey:"phoneNumber") as? String
cell?.zipCode?.text = person.value(forKey:"zipCode") as? String
return cell!
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 75
}
// Override to support conditional editing of the table view.
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
// MARK: - Navigation
@IBAction func unwindToContactsList(segue:UIStoryboardSegue) {
if let viewController = segue.source as? AddContactVC {
guard let _firstName: String = viewController.firstNameLbl.text,
let _lastName: String = viewController.lastNameLbl.text,
let _dob: String = viewController.dateOfBirthLbl.text,
let _phoneNumber: String = viewController.phoneNumberLbl.text,
let _zipCode: String = viewController.zipCodeLbl.text
else { return }
if _firstName != "" && _lastName != "" && _dob != "" && _phoneNumber != "" && _zipCode != "" {
if let indexPath = viewController.indexPathForContact {
update(indexPath: indexPath, firstName: _firstName, lastName: _lastName, dob: _dob, phoneNumber: _phoneNumber, zipCode: _zipCode)
print("Any updates?")
} else {
save(firstName: _firstName, lastName: _lastName, dob: _dob, phoneNumber: _phoneNumber, zipCode: _zipCode)
print("added to tableview") //this runs twice for some reason...
}
}
tableView.reloadData()
} else if let viewController = segue.source as? EditContactVC {
if viewController.isDeleted {
guard let indexPath: IndexPath = viewController.indexPath else { return }
let person = persons[indexPath.row]
delete(person, at: indexPath)
tableView.reloadData()
}
}
}
}
您可以使用 NSPredicate 的 sortDescriptors
属性 来过滤您的获取请求的结果。
查看 link 了解更多信息: How to sort a fetch in Core Data
这是一个示例代码,可以通过 NSFetchedResultsController
实现您的目标。我省略了一些不相关的代码。
class ContactViewController: UITableViewController {
let fetchedResultsController: NSFetchedResultsController<Contact>!
func searchTextFieldDidEditingChanged(_ textField: UITextField) {
let text = textField.text ?? ""
refetch(with: text)
}
// The key is you need change the predicate when searchTextField's
// value changed, and invoke proformFetch() again
func refetch(with text: String) {
let predicate = NSPredicate(format: "firstName CONTAINS %@", text)
fetchedResultsController.fetchRequest.predicate = predicate
do {
try self.fetchedResultsController.performFetch()
tableView.reloadData()
} catch let error as NSError {
loggingPrint("Error: \(error.localizedDescription)")
}
}
}
// MARK: - Table datasource
extension ContactViewController {
override func numberOfSections(in tableView: UITableView) -> Int {
return fetchedResultsController.sections!.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let sectionInfo = fetchedResultsController.sections![section]
return sectionInfo.numberOfObjects
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ContactCell", for: indexPath) as? PersonsCell
let contact = fetchedResultsController.object(at: indexPath)
cell.contact = contact
return cell!
}
}