如何使用已解析的 JSON 文件在表视图中添加搜索栏

how to add a searchbar in a tableview with a parsed JSON file

我已成功将具有以下数据模型的 JSON 文件解析到我的项目和表格视图中。

import Foundation

struct ActionResult: Codable {
    let data: [Datum]
}
struct Datum: Codable {
    let goalTitle, goalDescription, goalImage: String
    let action: [Action]
}
struct Action: Codable {
    let actionID: Int
    let actionTit: String
}

现在我正在尝试创建一个搜索栏来搜索“actionTitle”。我的表格视图有部分 headers 和行。

相关代码:

var filteredData: [Action]?
    
    let searchController = UISearchController()
  
    override func viewDidLoad() {
        super.viewDidLoad()
        title = "Search"
        searchController.searchBar.delegate = self
        filteredData = ????
        navigationItem.searchController = searchController
        parseJSON()
        
        
                func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
            filteredData = []
            if searchText == ""{
                filteredData = ????
            }
            else {
                for actions in ???? {
                if actions.lowercased().contains(searchText.lowercased()) {
                    filteredData.append(actions)
        }

                self.tableView.reloadData()
 }

我不知道在我有的地方使用什么代码????。

谢谢。

您想保留所有可用数据的实例 (allActions),并始终在 tableView 中显示您的筛选数据 (filteredData)。所以当没有什么可以过滤的时候,filteredData等于allActions除非你打算在搜索为空的时候隐藏所有数据)。

调用searchBar(_:,textDidChange:)时,可以在过滤器闭包上使用filter(_:) to evaluate if the item should be included. Apple's description

A closure that takes an element of the sequence as its argument and returns a Boolean value indicating whether the element should be included in the returned array.

不知道声明filteredData: [Action]?有没有什么具体原因,是不是调用了parseJSON()才填充数据?如果是这样——我建议初始化一个空数组并在数据可用时填充它们。

此外,parseData() 会生成 Datum 的实例吗?我相信你的这段代码不包括在内,所以我添加 datum: Datum?。 如果我错了,请提供更多信息 parseJSON() 填充的内容,我会更新我的答案。

var result: ActionResult? {
    didSet {
        guard let result = result else { return }
        allSectionDataActionMap = Dictionary(uniqueKeysWithValues: result.data.enumerated().map { ([=10=].0, ([=10=].1, [=10=].1.actions)) })
        updateFilteredData()
    }
}


var allSectionDataActionMap = [Int: (datum: Datum, actions: [Action])]()

// Maps the section index to the Datum & filtered [Action]
var filteredSectionDataActions = [Int: (datum: Datum, actions: [Action])]()

let searchController = UISearchController()

override func viewDidLoad() {
    super.viewDidLoad()

    title = "Search"
    searchController.searchBar.delegate = self
    navigationItem.searchController = searchController

    // ...
    parseJSON()
}

override func numberOfSections(in tableView: UITableView) -> Int {
    return filteredSectionDataActions.count
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return filteredSectionDataActions[section]?.actions.count ?? 0
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell") ?? UITableViewCell(style: .default, reuseIdentifier: "cell")
    if let action = filteredSectionDataActions[indexPath.section]?.actions[indexPath.row] {
        // setup cell for action
        cell.textLabel?.text = action.actionTitle
    }
    return cell
}

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    updateFilteredData(for: searchText.lowercased())
    tableView.reloadData()
}

func updateFilteredData(for searchText: String = String()) {

    if searchText.isEmpty {

        filteredSectionDataActions = allSectionDataActionMap

    } else {

        for (index, (datum, actions)) in allSectionDataActionMap {

            let filteredActions = actions.filter { [=10=].actionTitle.lowercased().contains(searchText) }

            if filteredActions.isEmpty {

                filteredSectionDataActions[index] = (datum, actions)

            } else {

                filteredSectionDataActions[index] = (datum, filteredActions)

            }
        }

    }

}