Как сгруппировать ячейки таблицы на основе поля в массиве JSON - PullRequest
0 голосов
/ 15 мая 2019

По сути, я использую данные 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 голосов
/ 15 мая 2019

Вы можете сгруппировать sequence на основе определенного ключа, используя один из Dictionary initializer,

init(grouping:by:)

. Приведенный выше метод init сгруппирует данный sequence на основеключ, который вы предоставите в его closure.

Кроме того, для анализа такого типа JSON вы можете легко использовать Codable вместо того, чтобы вручную выполнять всю работу.

Итак, для этого первого make 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
}

Попробуйте реализовать подход со всеми кусочками и дайте мне знать, если у вас возникнут какие-либо проблемы.

0 голосов
/ 15 мая 2019

Этого можно добиться, создав массив массивов.Так что-то вроде этого

[[{"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 для группировки по клиентам.Счетчик разделов будет числом внутренних массивов, и каждый раздел будет содержать столько строк, сколько чисел в этом массиве.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...