tableview.reloaddata() 在使用 coredata 时搜索栏取消按钮后不起作用
Posted
技术标签:
【中文标题】tableview.reloaddata() 在使用 coredata 时搜索栏取消按钮后不起作用【英文标题】:tableview.reloaddata() is not working after searchbar cancel button while using coredata 【发布时间】:2017-12-03 10:02:57 【问题描述】:我是 swift 新手。我正在使用 tableviewcontroller 并使用核心数据来显示我的搜索结果。搜索按钮工作正常,这是正确的,但每当我单击取消按钮时,它都会向我显示空白屏幕。我打印了项目数量的计数。它达到所需的计数并重置为零。我看了很多答案,但我还没有找到适合我的东西。我正在使用自定义单元格,即使在单击搜索之后,它也会显示搜索字符串的结果。
class CoinViewController: UITableViewController,UISearchResultsUpdating, UISearchBarDelegate
let searchController = UISearchController(searchResultsController: nil)
lazy var fetchedResultController: NSFetchedResultsController<NSFetchRequestResult> =
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: String(describing: Coin.self))
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "coinName", ascending: true)]
let frc = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: CoreDataStack.sharedInstance.persistentContainer.viewContext, sectionNameKeyPath: nil, cacheName: nil)
frc.delegate = self
return frc
()
override func viewDidLoad()
super.viewDidLoad()
self.getData()
self.navigationItem.title = "Coin List"
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.reloadData()
searchController.searchBar.delegate = self
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
definesPresentationContext = true
override func viewWillAppear(_ animated: Bool)
super.viewWillAppear(animated)
override func didReceiveMemoryWarning()
super.didReceiveMemoryWarning()
private func createCoinEntityFrom(dictionary: [String: AnyObject]) -> NSManagedObject?
let service = ApiService()
let context = CoreDataStack.sharedInstance.persistentContainer.viewContext
if let coinEntity = NSEntityDescription.insertNewObject(forEntityName: "Coin", into: context) as? Coin
coinEntity.algorithm = dictionary["Algorithm"] as? String
coinEntity.coinName = dictionary["CoinName"] as? String
if let imageURL = dictionary["ImageUrl"] as? String
coinEntity.imageURL = (service.baseImageurl) + imageURL
coinEntity.totalCoinSupply = dictionary["TotalCoinSupply"] as? String
return coinEntity
return nil
private func saveInCoreDataWith(array: [String: AnyObject])
_ = array.mapself.createCoinEntityFrom(dictionary: $1 as! [String : AnyObject])
do
try CoreDataStack.sharedInstance.persistentContainer.viewContext.save()
catch let error
print(error)
private func clearData()
do
let context = CoreDataStack.sharedInstance.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: String(describing: Coin.self))
do
let objects = try context.fetch(fetchRequest) as? [NSManagedObject]
_ = objects.map$0.mapcontext.delete($0)
CoreDataStack.sharedInstance.saveContext()
catch let error
print("ERROR DELETING : \(error)")
func showAlertWith(title: String, message: String, style: UIAlertControllerStyle = .alert)
let alertController = UIAlertController(title: title, message: message, preferredStyle: style)
let action = UIAlertAction(title: title, style: .default) (action) in
self.dismiss(animated: true, completion: nil)
alertController.addAction(action)
self.present(alertController, animated: true, completion: nil)
func getData()
do
try self.fetchedResultController.performFetch()
print("COUNT FETCHED FIRST: \(self.fetchedResultController.sections?[0].numberOfObjects)")
catch let error
print("ERROR: \(error)")
let service = ApiService()
service.getDataWith (result) in
switch result
case .Success(let data):
// for item in data
// self.coin.append(item as! Coin)
//
self.clearData()
self.saveInCoreDataWith(array: data)
case .Error(let message):
DispatchQueue.main.async
self.showAlertWith(title: "Error", message: message)
func updateSearchResults(for searchController: UISearchController)
search(searchController.searchBar.text!)
func search(_ searchText: String, scope: String="All")
var predicate:NSPredicate? = nil
let searchBar = searchController.searchBar
if (searchBar.text != nil)
predicate = NSPredicate(format: "(coinName contains [cd] %@) ", searchBar.text!, searchBar.text!)
self.fetchedResultController.fetchRequest.predicate = predicate
do
try self.fetchedResultController.performFetch()
catch let error
print("ERROR: \(error)")
tableView.reloadData()
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar)
if let searchTextField = searchController.searchBar.value(forKey: "_searchField") as? UITextField
searchTextField.clearButtonMode = .always
func searchBarCancelButtonClicked(_ searchBar: UISearchBar)
UIView.animate(withDuration: 0.3, animations: () -> Void in
searchBar.removeFromSuperview()
self.tableView.tableHeaderView = nil
searchBar.showsCancelButton = false
searchBar.resignFirstResponder()
self.fetchedResultController.fetchRequest.predicate = nil
do
try self.fetchedResultController.performFetch()
print("COUNT FETCHED FIRST: \(self.fetchedResultController.sections?[0].numberOfObjects)")
catch let error
print("ERROR: \(error)")
self.tableView.reloadData()
, completion: finished in
self.navigationController!.navigationBar.alpha = 1
self.navigationController!.isNavigationBarHidden = false
)
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
// #warning Incomplete implementation, return the number of rows
if let count = fetchedResultController.sections?.first?.numberOfObjects
print("----> \(count)")
return count
return 1
override func numberOfSections(in tableView: UITableView) -> Int
// #warning Incomplete implementation, return the number of sections
return 1
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
let cell = tableView.dequeueReusableCell(withIdentifier: "CoinCell", for: indexPath)
as! CoinCell
if let coin = fetchedResultController.object(at: indexPath) as? Coin
cell.coinNameLabel.text = coin.coinName
cell.coinValueLabel.text = coin.totalCoinSupply! + "$"
cell.coinImageUrl?.downloadImage(from: coin.imageURL!)
cell.percentageShift.text = "+12.56%"
return cell
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
return 120
@IBAction func searchFilter( _ sender: UIBarButtonItem)
tableView.tableHeaderView = searchController.searchBar
searchController.searchBar.becomeFirstResponder()
扩展 CoinViewController: NSFetchedResultsControllerDelegate func controller(_ controller: NSFetchedResultsController, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?)
switch type
case .insert:
self.tableView.insertRows(at: [newIndexPath!], with: .automatic)
case .delete:
self.tableView.deleteRows(at: [indexPath!], with: .automatic)
default:
break
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)
self.tableView.endUpdates()
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)
tableView.beginUpdates()
【问题讨论】:
【参考方案1】:这是在取消搜索时告诉您的功能:
func searchBarCancelButtonClicked(_ searchBar: UISearchBar)
如果您的结果被过滤,您应该重新加载它们并再次调用 reloadData()。
编辑 我认为这很清楚,但既然你在这里要求完整的代码,那就是:
func searchBarCancelButtonClicked(_ searchBar: UISearchBar)
self.fetchedResultController.fetchRequest.predicate = nil
do
try self.fetchedResultController.performFetch()
tableView.reloadData()
catch let error
print("ERROR: \(error)")
这样您无需过滤即可再次获取结果,然后重新加载表格视图。
【讨论】:
你能否明确告诉我我做错了什么并在我的代码中纠正。 您的代码没有显示您如何实现 UITableViewDataSource。您能否发布完整的表格视图控制器实现? 我卡住了一段时间 @YashAwasthi 是否调用了 searchBarCancelButtonClicked 函数?尝试放置断点并告诉我调试器是否在方法中执行。 是的。它正在步入这种方法。如我所说。第一次搜索后,它没有在 tableview 中显示任何数据。我再次执行搜索,它显示过滤结果。以上是关于tableview.reloaddata() 在使用 coredata 时搜索栏取消按钮后不起作用的主要内容,如果未能解决你的问题,请参考以下文章
使用通知中心和 tableview.reloaddata() 不刷新表视图
tableView.reloadData() 如何正确重新加载数据?
如何让 tableView.reloadData() 与核心数据正常工作?