Search code examples
iosswiftuitableviewdictionaryuipickerview

Swift Dictionary UIPickerView (key) and UITableView (value)


Img: Now the app: data does not change

Img: Now the app: data does not change

I'm currently developing an app using Swift where I use a UIPickerView and TableView (This applies to single view) . I want to change the key in the pickerView (myPickerView) the change take values in the TableView(myTableView) to the correct data (automatic) .

import UIKit

struct Cars {

    var carName: String!
    var carModel: [String]!

}

class ViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate, UITableViewDataSource, UITableViewDelegate {

    // Dictionary
   var myDictionary = [
    "BMW": ["M3", "M4", "M5"],
    "Porsche": ["Panamera", "911", "Cayenne"],
    "Audi": ["RS4", "RS6", "RS5"],
    "Mercedes": ["Class S", "SL", "AMG GTR"]
    ]

    // Array
    var allObjects = [Cars]()

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .white

        // Func - Constraint PickerView/TableView/Button
        setupUI()

        // PickerView Delegate/DataSource
        myPickerView.dataSource = self
        myPickerView.delegate = self

        // TableView Delegate/DataSource
        myTableView.delegate = self
        myTableView.dataSource = self

        myTableView.register(UITableViewCell.self, forCellReuseIdentifier: "cellId")

        // Loop key and value - myDictionary
        for (key, value) in myDictionary {

            allObjects.append(Cars(carName: key, carModel: value))
        }
    }

    // My TableView
    let myTableView: UITableView = {
       let tv = UITableView()
        tv.translatesAutoresizingMaskIntoConstraints = false
        return tv
    }()

    // My PickerView
    let myPickerView: UIPickerView = {
        let bp = UIPickerView()
        bp.translatesAutoresizingMaskIntoConstraints = false
        return bp
    }()

    // Button Open myPickerView and setup nameCar
    var myChoiceCarNameButton: UIButton = {
        let button = UIButton(type: .system)
        button.setTitle("Choice Car", for: .normal)
        button.tintColor = .black
        button.addTarget(self, action: #selector(handleChoiceCarName), for: .touchUpInside)
        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()

    // Target selector button "myChoiceCarNameButton"
    @objc func handleChoiceCarName() {
        print("Tapped choice car name ")

        view.layoutIfNeeded()
        UIView.animate(withDuration: 0.25, animations: {

            self.view.layoutIfNeeded()

        }) { (completed) in

            UIView.animate(withDuration: 0.25, animations: {

                self.myPickerView.alpha = 1
                self.view.layoutIfNeeded()
            })
        }
    }

    // Constraint button/pickerView/TableView
    private func setupUI() {

        view.addSubview(myChoiceCarNameButton)
        myChoiceCarNameButton.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20).isActive = true
        myChoiceCarNameButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        myChoiceCarNameButton.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
        myChoiceCarNameButton.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true


        view.addSubview(myPickerView)
        myPickerView.alpha = 0
        myPickerView.topAnchor.constraint(equalTo: myChoiceCarNameButton.bottomAnchor).isActive = true
        myPickerView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
        myPickerView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true


        view.addSubview(myTableView)
        myTableView.topAnchor.constraint(equalTo: myPickerView.bottomAnchor, constant: 10).isActive = true
        myTableView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
        myTableView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
        myTableView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 10).isActive = true
    }

    // MARK: - PickerViewDelegate/DataSource Methods

    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }

    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {

        if component == 0 {
            return allObjects.count
        } else {
            let selectedBody = pickerView.selectedRow(inComponent: 0)
            return allObjects[selectedBody].carName.count
        }
    }

    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {

        if component == 0 {
            return allObjects[row].carName
        } else {
            let selectedCar = pickerView.selectedRow(inComponent: 0)
            return allObjects[selectedCar].carName
        }
    }

    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {

        // Set the button title
        myChoiceCarNameButton.setTitle(allObjects[row].carName, for: .normal)

        view.layoutIfNeeded()
        UIView.animate(withDuration: 0.25, animations: {

            self.myPickerView.alpha = 0
            self.view.layoutIfNeeded()

        }) { (completed) in

            UIView.animate(withDuration: 0.25, animations: {

                self.view.layoutIfNeeded()
                self.myTableView.reloadData()
            })

        }

    } // End did select



    // MARK: - TableViewDelegate/DataSource Methods

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

        return allObjects[section].carModel.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cellId", for: indexPath)
        cell.backgroundColor = .green

        cell.textLabel?.font = UIFont.boldSystemFont(ofSize: 16)
        cell.textLabel?.text = allObjects[indexPath.section].carModel[indexPath.row]
        return cell
    }

} // End class

Maybe someone has found a similar situation and knows how to do it? Maybe someone an easier solution how to achieve this effect?


Solution

  • The problem is here :

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    
        return allObjects[section].carModel.count
    }
    

    You have to save the selected car in a variable when the choice has been made by the user, in the func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) function. Then in the numberOfRowsInSection function you have to use this variable :

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    
        return allObjects[selectedCarIndex].carModel.count
    }
    

    Also, you don't specify the func numberOfSections(in tableView: UITableView) -> Int delegate method, so I assume that the default value is always 1, so there is only 1 section in your UITableView. So in the func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int delegate method, the section will always be 1, so this is why you don't see any changes in the UITableView.