Tôi đã vật lộn vài ngày qua với việc tạo bộ lọc trong dự án Swift cho TableViewController
sử dụng Dữ liệu chính. Cuối cùng tôi đã tìm ra tôi cần phải sử dụng một UISearchController
, tạo ra một NSPredicate
cho searchController.searchBar
vvSwift UISearchController có dây trong Core Data Project, ứng dụng chạy, nhưng tìm kiếm không cập nhật
tôi thấy this post EXTREMELY helpful, nhưng sau khi mô hình của tôi TVC
sau khi dự án này, tôi tìm thấy "tất cả các đèn đang ở trên, nhưng chẳng ai nhấc máy của" . Tôi có thể tìm kiếm, vị từ được tạo trong searchBar
, thêm, xóa, v.v. nhưng các ô không cập nhật cho tìm kiếm. Tôi đang thiếu một cái gì đó, nhưng tôi không biết những gì.
Dưới đây là các phần có liên quan của mã của tôi.
class MasterViewController: UITableViewController, NSFetchedResultsControllerDelegate, UISearchControllerDelegate, UISearchResultsUpdating
// Properties that get instantiated later
var detailViewController: DetailViewController? = nil
var addNoteViewController:AddNoteViewController? = nil // I added this
var managedObjectContext: NSManagedObjectContext? = nil
// Added variable for UISearchController
var searchController: UISearchController!
var searchPredicate: NSPredicate? // I added this. It's optional on and gets set later
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.leftBarButtonItem = self.editButtonItem()
if let split = self.splitViewController {
let controllers = split.viewControllers
let context = self.fetchedResultsController.managedObjectContext
let entity = self.fetchedResultsController.fetchRequest.entity!
self.detailViewController = controllers[controllers.count-1].topViewController as? DetailViewController
}
// UISearchController setup
searchController = UISearchController(searchResultsController: nil)
searchController.dimsBackgroundDuringPresentation = false
searchController.searchResultsUpdater = self
searchController.searchBar.sizeToFit()
self.tableView.tableHeaderView = searchController?.searchBar
self.tableView.delegate = self
self.definesPresentationContext = true
}
// MARK: - UISearchResultsUpdating Delegate Method
// Called when the search bar's text or scope has changed or when the search bar becomes first responder.
func updateSearchResultsForSearchController(searchController: UISearchController) {
let searchText = self.searchController?.searchBar.text // steve put breakpoint
println(searchController.searchBar.text)
if let searchText = searchText {
searchPredicate = NSPredicate(format: "noteBody contains[c] %@", searchText)
self.tableView.reloadData()
println(searchPredicate)
}
}
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
var note: Note
if searchPredicate == nil {
note = self.fetchedResultsController.objectAtIndexPath(indexPath) as! Note
} else {
let filteredObjects = self.fetchedResultsController.fetchedObjects?.filter() {
return self.searchPredicate!.evaluateWithObject($0)
}
note = filteredObjects![indexPath.row] as! Note
}
let context = self.fetchedResultsController.managedObjectContext
context.deleteObject(note)
var error: NSError? = nil
if !context.save(&error) {
abort()
}
}
}
// MARK: - Fetched results controller
var fetchedResultsController: NSFetchedResultsController {
if _fetchedResultsController != nil {
return _fetchedResultsController!
}
let fetchRequest = NSFetchRequest()
// Edit the entity name as appropriate.
let entity = NSEntityDescription.entityForName("Note", inManagedObjectContext: self.managedObjectContext!)
fetchRequest.entity = entity
// Set the batch size to a suitable number.
fetchRequest.fetchBatchSize = 20
// Edit the sort key as appropriate.
let sortDescriptor = NSSortDescriptor(key: "noteTitle", ascending: false)
let sortDescriptors = [sortDescriptor]
fetchRequest.sortDescriptors = [sortDescriptor]
// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.managedObjectContext!, sectionNameKeyPath: nil, cacheName: "Master")
aFetchedResultsController.delegate = self
_fetchedResultsController = aFetchedResultsController
var error: NSError? = nil
if !_fetchedResultsController!.performFetch(&error) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
println("Unresolved error \(error), \(error?.userInfo)")
abort()
}
return _fetchedResultsController!
}
var _fetchedResultsController: NSFetchedResultsController? = nil
func controllerWillChangeContent(controller: NSFetchedResultsController) {
// self.tableView.beginUpdates() // ** original code, change if doesn't work** steve put breakpoint here
// ANSWER said this section is redundant, but keeping it b/c it doesn't crash
if searchPredicate == nil {
tableView.beginUpdates()
} else {
(searchController.searchResultsUpdater as! MasterViewController).tableView.beginUpdates()
}
}
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.searchResultsUpdater as! MasterViewController).tableView
}
switch type {
case .Insert:
self.tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade)
case .Delete:
self.tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade)
default:
return
}
}
Tôi nghĩ rằng sự cố của tôi "sống" ở đây trong phần này. Tự động điền đã là bạn của tôi đến đây, nhưng tôi không thấy "searchIndex
" được tham chiếu trong Tự động hoàn thành. Tôi nghĩ rằng tôi đang thiếu một cái gì đó, nhưng tôi không chắc chắn những gì hoặc làm thế nào.
Nếu bạn đã thực hiện điều này từ xa, cảm ơn bạn đã đọc. Here's the GitHub repo cho chi nhánh tôi đang làm việc.
func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
var tableView = UITableView()
if self.searchPredicate == nil {
tableView = self.tableView
} else {
tableView = (self.searchController.searchResultsUpdater as! MasterViewController).tableView
}
switch type {
case .Insert:
println("*** NSFetchedResultsChangeInsert (object)")
tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Fade)
case .Delete:
println("*** NSFetchedResultsChangeDelete (object)")
tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade)
case .Update:
println("*** NSFetchedResultsChangeUpdate (object)")
// TODO: need fix this
// ORIGINAL CODE
// self.configureCell(tableView.cellForRowAtIndexPath(indexPath!)!, atIndexPath: indexPath!) // original code
// PROSPECTIVE SOLUTION CODE
println("*** NSFetchedResultsChangeUpdate (object)")
if searchPredicate == nil {
self.configureCell(tableView.cellForRowAtIndexPath(indexPath!)!, atIndexPath: indexPath!) // original code
} else {
// Should search the do something w/ the UISearchControllerDelegate or UISearchResultsUpdating
// Instead of "indexPath", it should be "searchIndexPath"--How?
let cell = tableView.cellForRowAtIndexPath(searchIndexPath) as LocationCell // My cell is a vanilla cell, not a xib
let location = controller.objectAtIndexPath(searchIndexPath) as Location // My object is a "Note"
cell.configureForLocation(location) // This is from the other guy's code, don't think it's applicable to me
}
case .Move:
println("*** NSFetchedResultsChangeMove (object)")
tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade)
tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Fade)
default:
return
}
}
func controllerDidChangeContent(controller: NSFetchedResultsController) {
if self.searchPredicate == nil {
self.tableView.endUpdates()
} else {
println("controllerDidChangeContent")
(self.searchController.searchResultsUpdater as! MasterViewController).tableView.endUpdates()
}
}
Edit: mỗi @pbasdf, tôi thêm các phương pháp TableView.
// MARK: - Table View
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return self.fetchedResultsController.sections?.count ?? 0
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if self.searchPredicate == nil {
let sectionInfo = self.fetchedResultsController.sections![section] as! NSFetchedResultsSectionInfo
return sectionInfo.numberOfObjects
}
let sectionInfo = self.fetchedResultsController.sections![section] as! NSFetchedResultsSectionInfo
return sectionInfo.numberOfObjects
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
self.configureCell(cell, atIndexPath: indexPath)
return cell
}
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}
Tìm kiếm của bạnĐối tượng ủy quyền được đặt thành tự? Trong 'viewDidLoad':' searchController.delegate = self' và 'searchController.searchResultsUpdater = self' – Ian
Điều đó không làm gì cả, nhưng ứng dụng không đổ vỡ khi nó chạy.Não của tôi đã chiên trong ngày, nhưng tôi sẽ đào bới và xem liệu tôi có thiếu phương pháp đại biểu ở đâu đó để giữ nó không được cập nhật. Cảm ơn bạn đã tìm kiếm. – Adrian
Liên kết tới repo GitHub của bạn bị hỏng. Nhưng bạn có thể thêm các phương thức tableView dataSource (numberOfSectionsInTableview, numberOfRowsInSection, cellForRowAtIndexPath, v.v.) vào bài viết của bạn ở trên, thay vào đó. Cảm ơn. – pbasdf