UITableView not showing class array data

70 views Asked by At

I am trying to create an app that gets the input of the user and fills a class, then afterwards stores that data on an array that I want to retrieve and populate a UITableView.

My issue is that I can't figure it out for the life of me what is wrong exactly, since I learned how to code by myself, and I am sure that it will be something simple, yet, I just can't find out.

I am not getting any errors and searched for days to see if someone else had the same issue using an array of classes but no luck making it work so far.

I have tried to populate the class manually with pre defined strings, but this has not made any difference. I tried to print, and I see that nothing has been printed, hence why nothing is showing up on my UITableView. I have defined data source and delegate with no avail.

Here is my class and array:

class UserTrips {
        init(type: String = "Tourism", roundtrip: String = "True", departure: String = "March 10, 2024", arrival: String = "March 23, 2024", from: String = "YYZ", to: String = "OPO", vehicle: String = "Air") {
        }
    }
    
    let tripVariable = UserTrips()
    var tripsArray: [UserTrips] = [
        .init(type: "Tourism", roundtrip: "True", departure: "March 5, 2024", arrival: "March 10, 2024", from: "YYZ", to: "OPO", vehicle: "Air"),
        .init(type: "Tourism", roundtrip: "False", departure: "March 10, 2024", arrival: "March 23, 2024", from: "Toronto", to: "New York", vehicle: "Land")
        ]

Here is my viewDidLoad:

override func viewDidLoad() {
        super.viewDidLoad()
        
        self.tripsCellView.register(TripsTVC.nib(), forCellReuseIdentifier: TripsTVC.identifier)
        self.tripsCellView.delegate = self
        self.tripsCellView.dataSource = self
}

Here is tableView code:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return tripsArray.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell()
        let data = tripsArray[indexPath.row]
        
        if indexPath.row > 0 {
            let customCell = self.tripsCellView.dequeueReusableCell(withIdentifier: TripsTVC.identifier) as! TripsTVC
            customCell.configure(with: "Tourism", roundtrip: "True", departure: "March 10, 2024", arrival: "March 23, 2024", from: "YYZ", to: "OPO", vehicle: "Air")
            return customCell
        }
        
        return cell
    }

Any help would be very appreciated.

EDIT:

Current Code:

import UIKit

class Mainscreen: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    class UserTrips {
        
        init(type: String = "Tourism", roundtrip: String = "True", departure: String = "March 10, 2024", arrival: String = "March 23, 2024", from: String = "YYZ", to: String = "OPO", vehicle: String = "Air") {
        }
        
        var type: String = "Tourism"
        var roundtrip: String = "True"
        var departure: String = "March 10, 2024"
        var arrival: String = "March 23, 2024"
        var from: String = "YYZ"
        var to: String = "OPO"
        var vehicle: String = "Air"
    }
    
    let tripVariable = UserTrips()
    var tripsArray: [UserTrips] = [
        .init(type: "Tourism", roundtrip: "True", departure: "March 5, 2024", arrival: "March 10, 2024", from: "YYZ", to: "OPO", vehicle: "Air"),
        .init(type: "Tourism", roundtrip: "False", departure: "March 10, 2024", arrival: "March 23, 2024", from: "Toronto", to: "New York", vehicle: "Land")
        ]
    
    @IBOutlet weak var tripsCellView: UITableView!
    @IBOutlet weak var menuStack: UIStackView!
    @IBOutlet weak var addTripButton: UIButton!
    @IBOutlet weak var userAccountButton: UIButton!
    @IBOutlet weak var travelHistoryButton: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.tripsCellView.register(TripsTVC.nib(), forCellReuseIdentifier: TripsTVC.identifier)
        self.tripsCellView.delegate = self
        self.tripsCellView.dataSource = self

        self.travelHistoryButton.layer.cornerRadius = 20
        self.travelHistoryButton.layer.masksToBounds = true
        self.travelHistoryButton.layer.borderWidth = 5
        self.travelHistoryButton.layer.borderColor = CGColor(red: 255/255, green: 59/255, blue: 48/255, alpha: 1)
        self.menuStack.layer.cornerRadius = 20
        self.menuStack.layer.masksToBounds = true
        
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return tripsArray.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell()
        let data = tripsArray[indexPath.row]
        
        if indexPath.row > 0 {
            let customCell = self.tripsCellView.dequeueReusableCell(withIdentifier: TripsTVC.identifier) as! TripsTVC
            customCell.configure(with: data.type, roundtrip: data.roundtrip, departure: data.departure, arrival: data.arrival, from: data.from, to: data.to, vehicle: data.vehicle)
            customCell.dateFrom?.text = data.departure
            customCell.dateTo?.text = data.arrival
            customCell.tripInformation?.text = "\(data.from) to \(data.to) // \(data.to) to \(data.from)"
            return customCell
        }
        
        return cell
    }
    
    @IBAction func addTripButtonPressed(_ sender: UIButton) {
    }
    
    @IBAction func userAccountButtonPressed(_ sender: UIButton) {
    }
    
}
2

There are 2 answers

8
Swati On BEST ANSWER

I tried your code in Xcode and this is what is working.

class TripsTVC: UITableViewCell {

   @IBOutlet weak var label: UILabel!

   override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)
   }

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

   func configure(with: String, roundtrip: String, departure: String, arrival: String, from: String, to: String, vehicle: String) {
       label.text = with
   }
}

Make sure your label is connected in interface builder. There is no need to give any cell identifier. This works

self.tripsCellView.register(UINib(nibName: "TripsTVC", bundle: nil), forCellReuseIdentifier: String(describing: TripsTVC.self))

Here is the delegate method implementation

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let customCell = tableView.dequeueReusableCell(withIdentifier: String(describing: TripsTVC.self), for: indexPath) as! TripsTVC
    customCell.configure(with: "Tourism", roundtrip: "True", departure: "March 10, 2024", arrival: "March 23, 2024", from: "YYZ", to: "OPO", vehicle: "Air")
    return customCell
}

Make sure the connections in interface builder are accurate. The Custom Cell View should have the class TripsTVC and not the File Owner.

enter image description here

12
son On

I would like to refactor these things:

  1. Default parameter value within constructor
class UserTrip { //<- Class/Struct/Enum... name should be capitalized
  let type: String
  let roundtrip: String
  
  init(type: String = "Tourism", roundtrip: String = "True"...) {
    self.type = type
    self.roundtrip = roundtrip: String
    ...
  }
}

let trip = UserTrip()

In Swift, you can provide a default input parameter value like above. So you're able to omit these parameters if you don't really want to any pass value to it.


  1. It's better if you prepare the data (tripsArray) before cellForRow. Cause this function might be called multiple times, and that will leak of performance with the for loop. So I suggest this mock data:
var tripsArray: [UserTrip] = [
  .init(type: "Tourism", roundtrip: "True"),
  .init(type: "Flight", roundtrip: "false"),
  ...
]

By doing above, each cell will present a single element in tripsArray. Then cellForRow is much more readable:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  let cell = ...
  let data = tripsArray[indexPath.row]
  cell.configure(...)
  return cell
}