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() 与核心数据正常工作?

在后台和 tableView.reloadData() 中获取核心数据对象

Tableview.reloadData 不起作用

Swift:tableView.reloadData() 表中没有数据