UISearchBar 在 UITableView 中没有响应 JSON 数据

UISearchBar is not responding in UITableView with JSON data

根据标题,UISearchBar 未在 UITableView 中响应 JSON 数据。我无法使用搜索字段,你能帮帮我吗?

TableView 工作正常,数据显示它,但是当我在搜索字段中输入单词时没有任何反应。

也许问题出在这个扩展中? 扩展 ViewController:UISearchBarDelegate

import UIKit
  

          struct GalleryData: Decodable {
            
            let localized_name: String
            let primary_attr: String
            let attack_type: String
            let img: String
            
        }
    
    
    
    class ViewController: UIViewController {
        
        
        @IBOutlet weak var tableView: UITableView!
        
        
        var dataArray = [GalleryData]()
        var filteredArray = [String]()
        var shouldShowSearchResults = false
        @IBOutlet weak var searchBar: UISearchBar!
        
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            downloadJSON {
                self.tableView.reloadData()
            }
            
            tableView.delegate = self
            tableView.dataSource = self
            
            searchBar.delegate = self
            searchBar.placeholder = "Search here..."
            
        }
        
        
    }
    
    
    
    
    extension ViewController: UITableViewDelegate, UITableViewDataSource {
        
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            
            if shouldShowSearchResults {
                return filteredArray.count
            } else {
                return dataArray.count
            }
            
        }
        
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            
            let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
            
            if shouldShowSearchResults {
                cell.textLabel?.text = filteredArray[indexPath.row]
            }
            else {
                cell.textLabel?.text = dataArray[indexPath.row].localized_name.capitalized
            }
            
            
            return cell
            
        }
        
        func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            performSegue(withIdentifier: "showDetails", sender: self)
        }
        
        override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            if let destination = segue.destination as? DetailViewController {
                destination.galleryDataDetail = dataArray[(tableView.indexPathForSelectedRow?.row)!]
            }
        }
        
        func downloadJSON(completed: @escaping () -> ()) {
            
            let url = URL(string: "https://api.opendota.com/api/heroStats")
            
            URLSession.shared.dataTask(with: url!) { (data, response, error) in
                
                do {
                    self.dataArray = try JSONDecoder().decode([GalleryData].self, from: data!)
                    DispatchQueue.main.async {
                        completed()
                    }
                }
                catch {
                    print("JSON error")
                }
                
            }.resume()
            
        }
        
    }
    
    
    
    
    extension ViewController: UISearchBarDelegate {
        
        func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
            
            let searchString = searchBar.text
            
            filteredArray = dataArray.filter({ (country) -> Bool in
                                let countryText: NSString = country as NSString
                                return (countryText.range(of: searchString!, options: .caseInsensitive).location) != NSNotFound
                            })
            tableView.reloadData()
                }
            
        
        
        func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
            shouldShowSearchResults = true
            tableView.reloadData()
        }
        
        func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
            searchBar.text = ""
            shouldShowSearchResults = false
            tableView.reloadData()
        }
        
    
    }

尝试像这样更改您的代码

import UIKit
  
    struct GalleryData: Decodable 
    {    
        let localized_name: String
        let primary_attr: String
        let attack_type: String
        let img: String        
    }
    
    class ViewController: UIViewController 
    {    
        @IBOutlet weak var tableView: UITableView!
        @IBOutlet weak var searchBar: UISearchBar!
        
        var dataArray = [GalleryData]() 
        var filteredArray = [GalleryData]() {
            didSet {
                tableView.reloadData()
            }
        }
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            tableView.delegate = self
            tableView.dataSource = self
            
            searchBar.delegate = self
            searchBar.placeholder = "Search here..."
            
            downloadJSON()
        } 
    }
    
    extension ViewController: UITableViewDelegate, UITableViewDataSource {
        
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return filteredArray.count
        }
        
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
            
            cell.textLabel?.text = filteredArray[indexPath.row].localized_name.capitalized
            
            return cell            
        }
        
        func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            performSegue(withIdentifier: "showDetails", sender: self)
        }
        
        override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            if let destination = segue.destination as? DetailViewController {
                destination.galleryDataDetail = filteredArray[(tableView.indexPathForSelectedRow?.row)!]
            }
        }
        
        func downloadJSON() {
            let url = URL(string: "https://api.opendota.com/api/heroStats")
            
            URLSession.shared.dataTask(with: url!) { [unowned self] (data, response, error) in
                do {
                    self.dataArray = try JSONDecoder().decode([GalleryData].self, from: data!)
                    self.filteredArray = self.dataArray
                }
                catch {
                    print("JSON error")
                }
            }.resume()
        }
    }
    
    extension ViewController: UISearchBarDelegate 
    {    
        func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
            guard let searchText = searchBar.text else { return } 

            if (searchText == "") {
                    filteredArray = dataArray 
                    return
            }
                
            filteredArray = dataArray.filter { [=10=].localized_name.uppercased.contains(searchText.uppercased) }
        }

        func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
            searchBar.text = ""
        }
    }

首先将过滤后的数组声明为与数据源数组相同的类型效率更高

var dataArray = [GalleryData]()
var filteredArray = [GalleryData]()

textDidChange中检查搜索字符串是否为空并相应地设置shouldShowSearchResults

并且根本不需要 NSString 的桥梁

extension ViewController: UISearchBarDelegate {
    
    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        
        if searchText.isEmpty {
            shouldShowSearchResults = false
            filteredArray = []
        } else {
            filteredArray = dataArray.filter{ [=11=].localized_name.range(of: searchText, options: .caseInsensitive) != nil }
            shouldShowSearchResults = true
        }
        tableView.reloadData()
    }
    
    func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
        searchBar.text = ""
        shouldShowSearchResults = false
        tableView.reloadData()
    }
}

searchBarTextDidBeginEditing也不需要。

cellForRowAt中为单元格添加标识符并重复使用单元格

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
      let cell = tableView.dequeueReusableCell(withIdentifier: "GalleryCell", for: indexPath)
        
      let item = shouldShowSearchResults ? filteredArray[indexPath.row] : dataArray[indexPath.row]         
      cell.textLabel?.text = item.localized_name.capitalized            
      return cell  
}

请注意,如果显示搜索结果,segue 将不起作用(甚至会崩溃)

更复杂的解决方案是 UITableViewDiffableDataSource (iOS 13+)