gpt4 book ai didi

Swift UISearchController 在核心数据项目中连接,应用程序运行,但搜索不更新

转载 作者:IT王子 更新时间:2023-10-29 05:50:41 24 4
gpt4 key购买 nike

过去几天,我一直在努力在 Swift 项目中为使用 Core Data 的 TableViewController 创建过滤器。我终于发现我需要使用 UISearchController,为 searchController.searchBar 创建一个 NSPredicate,等等。

我找到了 this post EXTREMELY helpful ,但是在这个项目之后为我的 TVC 建模后,我发现“所有的灯都亮着,但没人在家”。我可以搜索,谓词是在 searchBar 中创建的,添加、删除等,但单元格不会针对搜索进行更新。我错过了什么,但我不知道是什么。

这是我的代码的相关部分。

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
}
}

我认为我的问题“存在”在本节中。到目前为止,自动完成一直是我的 friend ,但我没有看到自动完成中引用了“searchIndex”。 我想我错过了什么,但我不确定是什么或如何。

如果您已经读到这里,感谢您的阅读。 Here's the GitHub repo对于我正在工作的分支机构。

    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()
}

}

编辑:根据@pbasdf,我正在添加 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
}

最佳答案

问题在于您的 tableView 数据源方法:numberOfSectionsInTableview:tableView:numberOfRowsInSection:tableView:cellForRowAtIndexPath:。如果 searchPredicate 不是 nil,您需要这些方法中的每一个来返回不同的结果——就像您的 tableView:commitEditingStyle: 方法一样。我将使 filteredObjects 成为实例属性(在类的开头定义),以便所有这些方法都可以访问它:

var filteredObjects : [Note]? = nil

现在,当搜索文本发生变化时,您想要重建 filteredObjects 数组。因此,在 updateSearchResultsForSearchController 中,添加一行以根据新谓词重新计算它:

    if let searchText = searchText {
searchPredicate = NSPredicate(format: "noteBody contains[c] %@", searchText)
filteredObjects = self.fetchedResultsController.fetchedObjects?.filter() {
return self.searchPredicate!.evaluateWithObject($0)
} as [Note]?
self.tableView.reloadData()
println(searchPredicate)
}

我还建议(为简单起见)当您激活搜索时,结果将全部显示在一个部分中(否则您必须算出您的过滤结果属于多少部分 - 可能但很烦人):

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

接下来,如果 searchPredicate 不为 nil,则该部分中的行数将是 filteredObjects 的计数:

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if self.searchPredicate == nil {
let sectionInfo = self.fetchedResultsController.sections![section] as! NSFetchedResultsSectionInfo
return sectionInfo.numberOfObjects
} else {
return filteredObjects?.count ?? 0
}
}

最后,如果 searchPredicate 不为 nil,则需要使用 filteredObjects 数据而不是 fetchedResultsController 来构建单元格:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
if searchPredicate == nil {
self.configureCell(cell, atIndexPath: indexPath)
return cell
} else {
// configure the cell based on filteredObjects data
...
return cell
}
}

不确定你的单元格中有什么标签等,所以我留给你来排序。

关于Swift UISearchController 在核心数据项目中连接,应用程序运行,但搜索不更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28708865/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com