【问题标题】:How to load JSON array data into UITableView Section and Row using Swift?如何使用 Swift 将 JSON 数组数据加载到 UITableView 部分和行中?
【发布时间】:2019-12-21 11:18:12
【问题描述】:

我的场景,我正在尝试将JSON 数据加载到UITableView。在这里,问题是我的 JSON 有多个 array 和多个 values。我需要将数组 keys 作为 Tableview section 名称并将其全部 values 加载到相关的 cell 中。我正在使用codable 方法进行简单的 JSON 数据处理。现在,如何将数组键名(学校、办公室等)放入部分及其值相关的单元格中。

我的 JSON

https://api.myjson.com/bins/r763z

我的可编码

   struct Root : Decodable {
        let status : Bool
        let data: ResultData
    }

    struct ResultData : Decodable {
        let school, college, office, organisation, central : [Result]
    }

    struct Result : Decodable {
        let id, name, date : String
        let group : [String]
    }

我的 JSON 解码器代码

func loadJSON(){

        let urlPath = "https://api.myjson.com/bins/r763z"
        let url = NSURL(string: urlPath)
        let session = URLSession.shared
        let task = session.dataTask(with: url! as URL) { data, response, error in
            guard data != nil && error == nil else {
                print(error!.localizedDescription)
                return
            }
            do {

                let decoder = JSONDecoder()
                self.tableData = try decoder.decode(DivisionData.self, from: data!) // How to get section values and cell values and load table data
                DispatchQueue.main.async {

                    self.tableView.reloadData()

                }

            } catch { print(error) }
        }
        task.resume()
    }

Expected Output

【问题讨论】:

  • @vadian 你能帮忙吗?

标签: ios swift


【解决方案1】:

只需为不同的部分使用不同的数组即可。

var tableData: ResultData?

override func numberOfSections(in tableView: UITableView) -> Int {
    return 5
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    guard let tableData = tableData else { return 0 }
    switch section {
    case 0:
        return tableData.school.count
    case 1:
        return tableData.college.count
    case 2:
        return tableData.office.count
    case 3:
        return tableData.organisation.count
    case 4:
        return tableData.central.count
    default:
        return 0
    }
}

override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    switch section {
    case 0:
        return "School"
    case 1:
        return "College"
    case 2:
        return "Office"
    case 3:
        return "Organisation"
    case 4:
        return "Central"
    default:
        return nil
    }
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier, for: indexPath)

    // Get item
    var item: Result?
    switch section {
    case 0:
        item = tableData?.school[indexPath.row]
    case 1:
        item = tableData?.college[indexPath.row]
    case 2:
        item = tableData?.office[indexPath.row]
    case 3:
        item = tableData?.organisation[indexPath.row]
    case 4:
        item = tableData?.central[indexPath.row]
    default:
        break
    }

    if let item = item {
        // Configure the cell...
    }

    return cell
}

要获取您的数据,您需要像这样使用URLSession

func fetchData() {
    guard let url = URL(string: "https://api.myjson.com/bins/r763z") else { return }

    let task = URLSession.shared.dataTask(with: url) { data, response, error in
        if let error = error {
            print("An error occurred: \(error)")
        } else if let data = data, let response = response as? HTTPURLResponse, response.statusCode == 200 {
            let decoder = JSONDecoder()
            do {
                let json = try decoder.decode(Root.self, from: data)
                tableData = json.data
                // Reload table view
                DispatchQueue.main.async {
                    self.tableView.reloadData()
                }
            } catch {
                print("Decoding error: \(error)")
            }
        }
    }
    task.resume()
}

【讨论】:

  • 我的问题是如何将 JSON 数据加载到我的 tableview 中。上面你的例子看起来是静态的。
  • 您的问题不够清楚!我用代码更新了我的答案以获取您的数据
  • @TheFlow_ 非常感谢你我会尝试你的回答并在这里更新你,我也会更新我的问题
  • 我想我给了你你需要的答案。如果是这样,请考虑将我的答案标记为正确的
  • 非常感谢它帮助很大,但 vadian 给出的动态答案
【解决方案2】:

要有效地在部分中显示 JSON,您必须将 JSON 解码为具有 title 成员的结构

struct Root : Decodable {
    let status : Bool
    let sections : [Section]

    private enum CodingKeys : String, CodingKey { case status, data }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        status = try container.decode(Bool.self, forKey: .status)
        let data = try container.decode([String:[Result]].self, forKey: .data)
        sections = data.compactMap{ return $0.value.isEmpty ? nil : Section(title: $0.key, result: $0.value) }
    }
}

struct Section {
    let title : String
    let result : [Result]
}

struct Result : Decodable {
    let id, name, date : String
    let group : [String]
}

声明一个数据源数组

var sections = [Section]()

将结果赋值给数组

do {
    let decoder = try JSONDecoder().decode(Root.self,  from: data!)
    let status = decoder.status

    if status == true {
        sections = decoder.sections
        DispatchQueue.main.async {
            self.tableView.reloadData()
        }
    } else {

    }
} catch { print(error) }

相关的表视图数据源方法有

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

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return sections[section].result.count
}

override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    return sections[section].title
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath)
    let item = sections[indexPath.section].result[indexPath.row]
    // Update the UI
}

旁注:使用更有意义的名称命名您的结构。例如,一个数组应该以 plural 形式命名(就像我之前的建议一样)

【讨论】:

  • 哇。你怎么想的这么多。伟大的!我会在这里检查并更新你。非常感谢
  • 如果我单击 tableview 单元格,则可以获取单元格的所有值,因为我要将这些值传递给另一个视图控制器。如果可能的话更新它
  • 那是另一个问题。但无论如何从 model 而不是从 view 获取值
  • 不不,我只是要求 didSelectRowAt 获取所有数据。如果假设我的数组为空我不想显示该部分,则另一个与上述问题相关的疑问。是否有可能请给我一个提示,我两天以来一直在挣扎。否则需要在空白部分下显示一个带有空数据占位符的空单元格。
  • 对我的答案投反对票的原因是什么?这是一个非常有效的工作解决方案。
猜你喜欢
  • 2016-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多