How can I display the json data in a Swift SpreadsheetView

172 Views Asked by At

I am using a pod called SpreadsheetView to show data, from a json, in a grid but I don't know how to show them because with this pod it is necessary to invoke an array for each column. I would like to order this data from my json in the corresponding columns and also when touching a cell in a row I was taken to a view to show the related data.

Attached the code of what I have done.

The view that I use to display the data

import UIKit
import SpreadsheetView

class TiendasViewController: UIViewController, SpreadsheetViewDataSource, SpreadsheetViewDelegate, ConsultaModeloProtocol{

let headers = ["Sucursal", "Venta total", "Tickets", "Piezas", "Pzs/Ticket", "Ticket prom.", "Utilidad", "Última venta"]
  
    var feedItems = [DetallesConsulta]()
    
    func itemConsulta(LaConsulta: [DetallesConsulta]) {
        feedItems = LaConsulta
        self.tablaTiendas.reloadData()
        
    }
    
    var selectDato : DetallesConsulta = DetallesConsulta()
    
    private let tablaTiendas = SpreadsheetView()
    
    
    override func viewDidLoad() {
        
        super.viewDidLoad()
        
        let consultaModelo = ConsultaModelo()
        consultaModelo.ElDelegado = self
        consultaModelo.downloadConsulta()
        
        tablaTiendas.dataSource = self
        tablaTiendas.delegate = self
        
        tablaTiendas.contentInset = UIEdgeInsets(top: 4, left: 0, bottom: 4, right: 0)
        tablaTiendas.intercellSpacing = CGSize(width: 4, height: 1)
        tablaTiendas.gridStyle = .none
        
        
        tablaTiendas.gridStyle = .solid(width: 1, color: .blue)
        tablaTiendas.register(SucursalesCell.self, forCellWithReuseIdentifier: String(describing: SucursalesCell.self))
        tablaTiendas.register(DateCell.self, forCellWithReuseIdentifier: String(describing: DateCell.self))
       
        
        view.addSubview(tablaTiendas)
        print("Imprimiendo los feeditems: ", feedItems)
        // Do any additional setup after loading the view.
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        tablaTiendas.frame = CGRect(x: 0, y:216, width: view.frame.size.width, height: view.frame.size.height-100)
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        tablaTiendas.flashScrollIndicators()
    }
    
    func spreadsheetView(_ spreadsheetView: SpreadsheetView, cellForItemAt indexPath: IndexPath) -> Cell? {
        
        if case (0...(headers.count), 0) = (indexPath.column, indexPath.row) {
            
            let cell = spreadsheetView.dequeueReusableCell(withReuseIdentifier: String(describing: DateCell.self), for: indexPath) as! DateCell
            cell.label.text = headers[indexPath.column - 0]
            return cell
            
        } else if case(0, 1...(sucursales.count + 1)) = (indexPath.column, indexPath.row){
            
            let cell = spreadsheetView.dequeueReusableCell(withReuseIdentifier: String(describing: SucursalesCell.self), for: indexPath) as! SucursalesCell
            
            cell.label.text = sucursales[indexPath.row - 1]
            return cell
            
        }
       
       /*
        let cell = tablaTiendas.dequeueReusableCell(withReuseIdentifier: MyLabelCell.identifier, for: indexPath) as! MyLabelCell
        if indexPath.row == 0 {
            cell.setup(with: headers[indexPath.column])
            cell.backgroundColor = .systemBlue
        }
        return cell
        */
          
      return nil

    }
    

    func numberOfColumns(in spreadsheetView: SpreadsheetView) -> Int {
        return headers.count
    }
    
    func numberOfRows(in spreadsheetView: SpreadsheetView) -> Int {
        return 1 + sucursales.count
    }
    
    func spreadsheetView(_ spreadsheetView: SpreadsheetView, widthForColumn column: Int) -> CGFloat {
        return 200
    }
    
    func spreadsheetView(_ spreadsheetView: SpreadsheetView, heightForRow row: Int) -> CGFloat {
        if case 0 = row{
            return 24
        }else{
            return 55
        }
        
    }
    
    func frozenColumns(in spreadsheetView: SpreadsheetView) -> Int {
        return 1
    }

}

class MyLabelCell: Cell {
    
    private let label = UILabel()
    
    public func setup(with text: String){
        label.text = text
        label.textAlignment = .center
        contentView.addSubview(label)
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        label.frame = contentView.bounds
    }
}

class DateCell: Cell {
    let label = UILabel()

    override init(frame: CGRect) {
        super.init(frame: frame)

        label.frame = bounds
        label.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        label.font = UIFont.boldSystemFont(ofSize: 15)
        label.textAlignment = .center

        contentView.addSubview(label)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
}

class SucursalesCell: Cell {
    let label = UILabel()

    override init(frame: CGRect) {
        super.init(frame: frame)

        label.frame = bounds
        label.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        label.font = UIFont.monospacedDigitSystemFont(ofSize: 12, weight: UIFont.Weight.medium)
        label.textAlignment = .center

        contentView.addSubview(label)
    }

    override var frame: CGRect {
        didSet {
            label.frame = bounds.insetBy(dx: 6, dy: 0)
        }
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
}

The model to download the json

import UIKit
import Foundation


protocol ConsultaModeloProtocol: AnyObject {
    func itemConsulta (LaConsulta: [DetallesConsulta])
}

var fechaPresente: String = ""
var fechaPasada: String = ""


let elToken : String = UserDefaults.standard.string(forKey: "token")!
let helper = Helper()

class ConsultaModelo: NSObject {
    
    weak var ElDelegado : ConsultaModeloProtocol!
    
    let URLPath = helper.host+"tiendas"
    
    func downloadConsulta(){
        
        var request = URLRequest(url: URL(string: URLPath)!)
        request.addValue("application/json", forHTTPHeaderField: "Accept")
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        request.addValue("Bearer \(elToken)", forHTTPHeaderField: "Authorization")
        
        request.httpMethod = "POST"
        
        let SessionDefault = Foundation.URLSession(configuration: URLSessionConfiguration.ephemeral)
        URLCache.shared.removeAllCachedResponses()
        
        let task = SessionDefault.dataTask(with: request){
            (data, response, error)in
            if error != nil {
                print("Error al descargar la consulta")
            }else{
                print("Datos descargados")
                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()
        var detalles = [DetallesConsulta]()
        
        for i in 0 ..< jsonResult.count{
            
            jsonElement = jsonResult[i] as! NSDictionary
            let detalle = DetallesConsulta()
            
            let Fecha = jsonElement["Fecha"]
            let Sucursal = jsonElement["Sucursal"]
            let Suc = jsonElement["Suc"]
            let VentaTotal = jsonElement["Venta_Total"]
            let NoFolios = jsonElement["N_Folios"]
            let Piezas = jsonElement["Piezas"]
            let PzaxTicket = jsonElement["PzaxTicket"]
            let TicketPromedio = jsonElement["TicketPromedio"]
         
            detalle.Fecha = Fecha as? String
            detalle.Sucursal = Sucursal as? String
            detalle.Suc = Suc as? String
            detalle.VentaTotal = VentaTotal as? String
            detalle.NoFolios = NoFolios as? Int
            detalle.Piezas = Piezas as? String
            detalle.PzaxTicket = PzaxTicket as? String
            detalle.TicketPromedio = TicketPromedio as? String
            
            detalles.append(detalle)
            
        }
        
        DispatchQueue.main.async(execute: { ()-> Void in
            
            self.ElDelegado.itemConsulta(LaConsulta: detalles)
        })
        
    }
 
    
    
}

The details

import UIKit

class DetallesConsulta: NSObject {

    var Fecha: String?
    var Sucursal: String?
    var Suc: String?
    var VentaTotal: String?
    var NoFolios: Int?
    var Piezas: String?
    var PzaxTicket: String?
    var TicketPromedio: String?

    override init(){

    }

    init(Fecha: String, Sucursal: String, Suc: String, VentaTotal: String, NoFolios: Int, Piezas: String, PzaxTicket: String, TicketPromedio: String){
        self.Fecha = Fecha
        self.Sucursal = Sucursal
        self.Suc = Suc
        self.VentaTotal = VentaTotal
        self.NoFolios = Int(NoFolios)
        self.Piezas = Piezas
        self.PzaxTicket = PzaxTicket
        self.TicketPromedio = TicketPromedio

    }
    override var description: String{

        return "Fecha: \(Fecha), Sucursal: \(Sucursal), Suc: \(Suc), VentaTotal: \(VentaTotal), NoFolios: \(NoFolios), Piezas: \(Piezas), PzaxTicket: \(PzaxTicket), TicketPromedio: \(TicketPromedio)"

    }

}

JSON Response

[
    {
        "Fecha": "2022-11-17",
        "Sucursal": "SCALPERS PUEBLA",
        "Suc": "004",
        "Venta_Total": "xxxxxx.xxxxxxxxx",
        "N_Folios": 12,
        "Piezas": "xx.000",
        "PzaxTicket": "x.x",
        "TicketPromedio": "xxxx.x"
    },
    {
        "Fecha": "2022-11-17",
        "Sucursal": "SCALPERS SATELITE",
        "Suc": "005",
        "Venta_Total": "xxxxx.xxx",
        "N_Folios": xx,
        "Piezas": "xx.000",
        "PzaxTicket": "x.x",
        "TicketPromedio": "xxxxx.xxxx"
    },
    {
        "Fecha": "2022-11-17",
        "Sucursal": "SCALPERS OUTLET QUERETARO",
        "Suc": "006",
        "Venta_Total": "xxx.xxxxxxxxxx",
        "N_Folios": 4,
        "Piezas": "6.000",
        "PzaxTicket": "1.5",
        "TicketPromedio": "1419.5"
    },
    {
        "Fecha": "2022-11-17",
        "Sucursal": "SCALPERS ONLINE",
        "Suc": "xxxx",
        "Venta_Total": "xxxxx.xxxxxxx",
        "N_Folios": 15,
        "Piezas": "45.000",
        "PzaxTicket": "3.0",
        "TicketPromedio": "1930.5"
    }
]

I hope you can help me.

Thank you.

I downloaded the data from the json and would like to have it displayed in a grid table with this pod.

1

There are 1 best solutions below

1
vadian On

Your code is too complicated and too objective-c-ish. Never use NSArray/NSDictionary in Swift (except in a few rare CoreFoundation APIs)

To decode the data use Decodable. This is just a small part of the JSON as your class and the hard-coded data are quite different

let jsonString = """
[{"Sucursal":"Hamleys", "Venta_Total":"$1", "Piezas":"10"},
{"Sucursal":"Bobby Brown", "Venta_Total":"$1", "Piezas":"20"}]
"""

Create a struct conforming to Decodable and add CodingKeys to get rid of the capitalized keys. Maybe it's even possible with the .convertFromSnakeCase strategy

struct DetallesConsulta: Decodable {
    var sucursal: String
    var ventaTotal: String
    var piezas: String
    
    private enum CodingKeys: String, CodingKey {
        case sucursal = "Sucursal", ventaTotal = "Venta_Total", piezas = "Piezas"
    }
}

Then decode the data and to get arrays of the properties map the data.

do {
    let result = try JSONDecoder().decode([DetallesConsulta].self, from: Data(jsonString.utf8))
    let sucursales = result.map(\.sucursal)
    let vtaTotal = result.map(\.ventaTotal)
    let piezas = result.map(\.piezas)
    print(sucursales, vtaTotal, piezas)
} catch {
    print(error)
}