【问题标题】:Grouped sections not displaying in tableview分组部分未显示在表格视图中
【发布时间】:2019-10-03 18:50:18
【问题描述】:

我的整个表格视图都是以编程方式编写的,数据来自 JSON。我正在尝试按customer 对单元格进行分组,代码似乎是正确的,但根本没有显示任何部分。

代码如下:

Portfolios.swift

import UIKit

    struct Portfolios: Codable {
        let customer, serial, rma, model: String
        let manufacturer: String
    }

PortfolioController.swift

import UIKit

class PortfolioController: UITableViewController {

    var portfolios = [Portfolios]()
    var portfoliosDic = [String:[Portfolios]]()

    override func viewDidLoad() {
        super.viewDidLoad()
        navigationController?.navigationBar.prefersLargeTitles = true
        view.backgroundColor = UIColor.blue
        navigationItem.title = "Customer"
        fetchJSON()
    }

     func fetchJSON(){
        let urlString = "https://www.example.com/example/example.php"
        guard let url = URL(string: urlString) else { return }
        URLSession.shared.dataTask(with: url) { (data, _, error) in
            DispatchQueue.main.async {
                if let error = error {
                    print("Failed to fetch data from url", error)
                    return
                }
                guard let data = data else { return }
                do {

                    let decoder = JSONDecoder()
                    decoder.keyDecodingStrategy = .convertFromSnakeCase
                    let res = try JSONDecoder().decode([Portfolios].self, from: data)
                    self.portfoliosDic = Dictionary(grouping: res, by: { $0.customer})
                    DispatchQueue.main.async {
                        self.tableView.reloadData()
                    }
                    self.portfolios = try decoder.decode([Portfolios].self, from: data)

                    self.tableView.reloadData()

                } catch let jsonError {
                    print("Failed to decode json", jsonError)
                }

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

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        let keys = Array(portfoliosDic.keys)
        let item = portfoliosDic[keys[section]]!
        return item.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell(style: .subtitle, reuseIdentifier: "cellId")
            let keys = Array(portfoliosDic.keys)
            let arr = portfoliosDic[keys[indexPath.section]]!
            let customer = arr[indexPath.row]


let titleStr = [customer.serial, customer.manufacturer, customer.model].compactMap { $0 }.joined(separator: " - ")

        //cell.textLabel?.text = titleStr




        print(titleStr)
        // Get references to labels of cell
        cell.textLabel!.text = customer.serial


        return cell
    }

}

更新:

因为它是一个 UIViewController Xcode告诉我删除override func

我添加了@IBOutlet weak var tableView: UITableView!

(由于某种原因,最终结果是一个空表)

改用 UITableViewController:

import UIKit

class CustomerViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    @IBOutlet weak var tableView: UITableView!
    var sections = [Section]()

    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cellId")
        navigationController?.navigationBar.prefersLargeTitles = true
        fetchJSON()
    }

    func fetchJSON(){
        let urlString = "https://www.example.com/example/example.php"
        guard let url = URL(string: urlString) else { return }
        URLSession.shared.dataTask(with: url) { (data, _, error) in
            DispatchQueue.main.async {
                if let error = error {
                    print("Failed to fetch data from url", error)
                    return
                }
                guard let data = data else { return }
                do {
                    let decoder = JSONDecoder()
                    decoder.keyDecodingStrategy = .convertFromSnakeCase
                    let res = try decoder.decode([Portfolios].self, from: data)
                    let grouped = Dictionary(grouping: res, by: { $0.customer })
                    let keys = grouped.keys.sorted()
                    self.sections = keys.map({Section(name: $0, items: grouped[$0]!)})

                    DispatchQueue.main.async {
                        self.tableView.reloadData()
                    }
                } catch {
                    print("Failed to decode json", error)
                }

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

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

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

     func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cellId", for: indexPath)
        let section = sections[indexPath.section]
        let item = section.items[indexPath.row]
        let titleStr = "\(item.serial) - \(item.manufacturer) - \(item.model)"
        cell.textLabel!.text = titleStr
        return cell
    }

}

【问题讨论】:

    标签: ios json swift uitableview


    【解决方案1】:

    首先你为什么要对 JSON 进行两次解码?

    没有部分显示,因为方法titleForHeaderInSection 没有实现。

    无论如何,代码都不可靠,因为不能保证部分的顺序。我建议为这些部分创建另一个结构。

    struct Section {
        let name : String
        let items : [Portfolios]
    }
    
    struct Portfolios: Decodable {
        let customer, serial, rma, model: String
        let manufacturer: String
    }
    

    删除portfoliosportfoliosDic并声明数据源数组

    var sections = [Section]()
    

    对 JSON 进行分组,对键进行排序并将字典映射到 Section 实例

    do {
        let decoder = JSONDecoder()
        decoder.keyDecodingStrategy = .convertFromSnakeCase
        let res = try decoder.decode([Portfolios].self, from: data)
        let grouped = Dictionary(grouping: res, by: { $0.customer })
        let keys = grouped.keys.sorted()
        self.sections = keys.map({Section(name: $0, items: grouped[$0]!)})
    
        DispatchQueue.main.async {
            self.tableView.reloadData()
        }
    } catch {
        print("Failed to decode json", error)
    }
    

    表视图数据源和委托方法是

    override func numberOfSections(in tableView: UITableView) -> Int {
        return sections.count
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        let section = sections[section]
        return section.items.count
    }
    
    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return sections[section].name
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cellId", for: indexPath)
        let section = sections[indexPath.section]
        let item = section.items[indexPath.row]
        let titleStr = "\(item.serial) - \(item.manufacturer) - \(item.model)"
        cell.textLabel!.text = titleStr
        return cell
    }
    

    注意:

    总是cellForRowAt中的单元格出列

    【讨论】:

    • 感谢您的帮助,但如果不是 UITableViewController 而只是 UIViewController 怎么办?
    • 可以吗:import UIKit class CustomerViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { @IBOutlet weak var tableView: UITableView!
    • 是的,当然,连接IB中的表格视图。如果是UITableViewController,您必须override 数据源和委托方法
    • 请查看更新后的帖子。 tableview 出来是空的
    • 请将控制器恢复为UITableViewController 并覆盖方法。我更新了答案。如果单元格是在目标表格视图中设计的,那么您不得注册单元格。删除该行。
    猜你喜欢
    • 2013-07-21
    • 2016-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多