如何基于JSON数组中的字段对tableview单元格进行分组

时间:2019-05-15 05:00:56

标签: ios json swift tableview

基本上,我在使用JSON数据创建数组并形成表格视图。

我希望表格单元格通过JSON数组中的字段之一进行分组。

这是JSON数据的样子:

[{"customer":"Customer1","number":"122039120},{"customer":"Customer2","number":"213121423"}]

每个number需要按每个customer分组。

这怎么办?

这是我使用表实现JSON数据的方式:

CustomerViewController.swift

import UIKit

class CustomerViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, FeedCustomerProtocol {

    var feedItems: NSArray = NSArray()
    var selectedStock : StockCustomer = StockCustomer()
    let tableView = UITableView()
    @IBOutlet weak var customerItemsTableView: UITableView!

    override func viewDidLoad() {

        super.viewDidLoad()



        //set delegates and initialize FeedModel
        self.tableView.allowsMultipleSelection = true
        self.tableView.allowsMultipleSelectionDuringEditing = true

        self.customerItemsTableView.delegate = self
        self.customerItemsTableView.dataSource = self

        let feedCustomer = FeedCustomer()

        feedCustomer.delegate = self
        feedCustomer.downloadItems()

            }


    }


    func itemsDownloaded(items: NSArray) {

        feedItems = items
        self.customerItemsTableView.reloadData()
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // Return the number of feed items

        print("item feed loaded")
        return feedItems.count

    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        // Retrieve cell

        let cell = tableView.dequeueReusableCell(withIdentifier: "customerGoods", for: indexPath) as? CheckableTableViewCell

        let cellIdentifier: String = "customerGoods"
        let myCell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)!

        // Get the stock to be shown
        let item: StockCustomer = feedItems[indexPath.row] as! StockCustomer
        // Configure our cell title made up of name and price


        let titleStr = [item.number].compactMap { $0 }.joined(separator: " - ")


        return myCell
    }

    func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
        tableView.cellForRow(at: indexPath)?.accessoryType = .none
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {


        tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark

        let cellIdentifier: String = "customerGoods"
        let myCell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)!
        myCell.textLabel?.textAlignment = .left


    }

}

FeedCustomer.swift:

import Foundation

protocol FeedCustomerProtocol: class {
    func itemsDownloaded(items: NSArray)
}


class FeedCustomer: NSObject, URLSessionDataDelegate {



    weak var delegate: FeedCustomerProtocol!

    let urlPath = "https://www.example.com/example/test.php"

    func downloadItems() {

        let url: URL = URL(string: urlPath)!
        let defaultSession = Foundation.URLSession(configuration: URLSessionConfiguration.default)

        let task = defaultSession.dataTask(with: url) { (data, response, error) in

            if error != nil {
                print("Error")
            }else {
                print("stocks downloaded")
                self.parseJSON(data!)
            }

        }

        task.resume()
    }

    func parseJSON(_ data:Data) {

        var jsonResult = NSArray()

        do{
            jsonResult = try JSONSerialization.jsonObject(with: data, options:JSONSerialization.ReadingOptions.allowFragments) as! NSArray

        } catch let error as NSError {
            print(error)

        }

        var jsonElement = NSDictionary()
        let stocks = NSMutableArray()

        for i in 0 ..< jsonResult.count
        {

            jsonElement = jsonResult[i] as! NSDictionary

            let stock = StockCustomer()

            //the following insures none of the JsonElement values are nil through optional binding
            if let number = jsonElement[“number”] as? String,
                let customer = jsonElement["customer"] as? String,

            {

                stock.customer = customer
                stock.number = number
            }

            stocks.add(stock)

        }

        DispatchQueue.main.async(execute: { () -> Void in

            self.delegate.itemsDownloaded(items: stocks)

        })
    }
}

StockCustomer.swift:

import UIKit

class StockCustomer: NSObject {

    //properties of a stock

    var customer: String?
    var number: String?


    //empty constructor

    override init()
    {

    }

    //construct with @name and @price parameters

    init(customer: String) {

        self.customer = customer



    }



    override var description: String {
        return "Number: \(String(describing: number)), customer: \(String(describing: customer))"

    }

}

2 个答案:

答案 0 :(得分:0)

您可以通过创建一个数组数组来实现。像这样

[[{"customer": "customer1", "number": "123"}, {"customer": "customer1", "number": "456"}], [{"customer": "customer2", "number": "678"}, {"customer": "customer2", "number": "890"}]]

这不是可用于分组的唯一数据结构。另一种可能性是:

{"customer1": [{"customer": "customer1", "number": "123"}, {"customer": "customer1", "number": "456"}], "customer2": [{"customer": "customer2", "number": "678"}, {"customer": "customer2", "number": "890"}]}

然后,您可以使用UITableView sections按客户分组。节数将是内部数组的数量,每个节将包含与该内部数组中的数字一样多的行。

答案 1 :(得分:0)

您可以使用sequence Dictionary之一基于特定的密钥对initializer进行分组,

init(grouping:by:)

上述方法init将根据您将在其sequence中提供的密钥对给定的closure进行分组。

此外,要解析此类JSON,您可以轻松地使用Codable而不是手动完成所有工作。

因此,首先使StockCustomer符合Codable协议。

class StockCustomer: Codable {
    var customer: String?
    var number: String?
}

接下来,您可以像这样解析数组:

func parseJSON(data: Data) {
    do {
        let items = try JSONDecoder().decode([StockCustomer].self, from: data)
        //Grouping the data based on customer
        let groupedDict = Dictionary(grouping: items) { $0.customer } //groupedDict is of type - [String? : [StockCustomer]]
        self.feedItems = Array(groupedDict.values)
    } catch {
        print(error.localizedDescription)
    }
}

在此处详细了解init(grouping:by:)https://developer.apple.com/documentation/swift/dictionary/3127163-init

使feedItems类型的CustomerViewController中的[[StockCustomer]]对象

现在,您可以通过以下方式实现UITableViewDataSource方法:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.feedItems.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "customerGoods", for: indexPath) as! CheckableTableViewCell
    let items = self.feedItems[indexPath.row]
    cell.textLabel?.text = items.compactMap({$0.number}).joined(separator: " - ")
    //Configure the cell as per your requirement
    return cell
}

尝试用所有零碎的方法来实现该方法,并在遇到任何问题时通知我。