Search code examples
arraysswiftuibuttonsubview

Change title of array of UIButtons


i have an array of buttons and I try to change the name of the buttons but I don't know how to access to all buttons when the array randomPokemons get new data in the function didSet.

I can change the title if I use a sender, but I want to find all buttons with tag 10 or the best way to find the buttons and iterate to change the name to new Pokemon name when the array randomPokemons get new data.

class MainViewController: UIViewController {
    private var stackView: UIStackView!
    private var pokemonImage: UIImageView!
    private var titleLabel: UILabel!
    private var scoreLabel: UILabel!
    private var pokemonNameLabel: UILabel!

    var randomPokemons: [PokemonModel] = []{
        didSet {
            setButtonTitles()
        }
    }
    var correctAnswer: String = ""
    var correctAnswerImage: String = ""

    lazy var game = GameModel()

    // MARK: - Properties

    weak var coordinator: Coordinator?
    weak var context: Context?
    var viewModel: MainViewModel!

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemGray6
        viewModel.apiCaller.delegate = self

        setUpView()
        setUpLayout()
        viewModel.fetchPokemon()
    }

    private func setUpView() {
        titleLabel = UILabel()
        titleLabel.translatesAutoresizingMaskIntoConstraints = false
        titleLabel.text = "¿Who is that Pokemon?"
        titleLabel.font = UIFont(name: "Arial Rounded MT Bold", size: 24)
        titleLabel.numberOfLines = 0
        titleLabel.textAlignment = .center

        scoreLabel = UILabel()
        scoreLabel.translatesAutoresizingMaskIntoConstraints = false
        scoreLabel.text = "Score: 0"
        scoreLabel.numberOfLines = 0
        scoreLabel.textAlignment = .center

        pokemonImage = UIImageView(image: viewModel.getPokemonImage())
        pokemonImage.translatesAutoresizingMaskIntoConstraints = false
        pokemonImage.contentMode = .scaleAspectFit

        pokemonNameLabel = UILabel()
        pokemonNameLabel.translatesAutoresizingMaskIntoConstraints = false
        pokemonNameLabel.text = "Yes, is a Pikachu"
        pokemonNameLabel.numberOfLines = 0
        pokemonNameLabel.textAlignment = .center

        /*
         nameOption2Button = UIButton(type: .system)
         nameOption2Button.translatesAutoresizingMaskIntoConstraints = false
         nameOption2Button.setTitle(viewModel.getTitleButton(), for: .normal)
         nameOption2Button.setTitleColor(.black, for: .normal)
         nameOption2Button.backgroundColor = .white
         nameOption2Button.addTarget(self, action: #selector(option2Pressed), for: .touchUpInside)
          */

        // stackView = UIStackView(arrangedSubviews: [nameOption1Button, nameOption2Button, nameOption3Button, nameOption4Button])
        stackView = UIStackView()
        stackView.translatesAutoresizingMaskIntoConstraints = false
        stackView.axis = .vertical
        stackView.distribution = .equalSpacing
        stackView.spacing = 24

        // UIButtons
        ["Pokemon 1", "Pokemon 2", "Pokemon 3", "Pokemon 4"].forEach { pokemonName in
            let button = UIButton(type: .system)
            button.translatesAutoresizingMaskIntoConstraints = false
            button.setTitle(pokemonName, for: .normal)
            button.setTitleColor(.black, for: .normal)
            button.backgroundColor = .white
            button.heightAnchor.constraint(equalToConstant: 50).isActive = true
            button.layer.shadowOffset = CGSize(width: 0.0, height: 2.0)
            button.layer.shadowOpacity = 1.0
            button.layer.shadowRadius = 0
            button.layer.masksToBounds = false
            button.layer.cornerRadius = 10.0
            button.tag = 10
            button.addTarget(self, action: #selector(optionPressed), for: .touchUpInside)

            stackView.addArrangedSubview(button)
        }
    }

    private func setUpLayout() {
        view.addSubview(titleLabel)
        view.addSubview(scoreLabel)
        view.addSubview(pokemonImage)
        view.addSubview(pokemonNameLabel)
        view.addSubview(stackView)

        /*
         [nameOption1Button, nameOption2Button, nameOption3Button, nameOption4Button].forEach {
             $0?.heightAnchor.constraint(equalToConstant: 50).isActive = true
         }
          */

        NSLayoutConstraint.activate([
            titleLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            titleLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),

            scoreLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 2),
            scoreLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),

            pokemonImage.topAnchor.constraint(equalTo: scoreLabel.bottomAnchor, constant: 50),
            pokemonImage.centerXAnchor.constraint(equalTo: view.centerXAnchor),

            pokemonNameLabel.topAnchor.constraint(equalTo: pokemonImage.bottomAnchor, constant: 2),
            pokemonNameLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),

            stackView.topAnchor.constraint(equalTo: pokemonNameLabel.bottomAnchor, constant: 40),
            stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            // Width anchor 20 left x 20 right
            stackView.widthAnchor.constraint(equalToConstant: view.bounds.width - 40),
        ])
    }

    @objc func optionPressed(sender: UIButton!) {
        if let buttonTag = sender?.tag {
            print(buttonTag)
        }
    }
    
    func setButtonTitles(){
         button.setTitle(randomPokemons[safe: index]?.name.capitalized, for: .normal)
    }
}

Solution

  •     // Array to store references to buttons
        var buttons: [UIButton] = []
        var randomPokemons: [PokemonModel] = [] {
          didSet {
              setButtonTitles()
          }
        }
        
        // UIButtons
        ["Pokemon 1", "Pokemon 2", "Pokemon 3", "Pokemon 4"].enumerated().forEach { index, pokemonName in
            let button = UIButton(type: .system)
            button.translatesAutoresizingMaskIntoConstraints = false
            button.setTitle(pokemonName, for: .normal)
            button.setTitleColor(.black, for: .normal)
            button.backgroundColor = .white
            button.heightAnchor.constraint(equalToConstant: 50).isActive = true
            button.layer.shadowOffset = CGSize(width: 0.0, height: 2.0)
            button.layer.shadowOpacity = 1.0
            button.layer.shadowRadius = 0
            button.layer.masksToBounds = false
            button.layer.cornerRadius = 10.0
            button.tag = 10
            button.addTarget(self, action: #selector(optionPressed), for: .touchUpInside)
        
            stackView.addArrangedSubview(button)
            
            // Add the button to the array
            buttons.append(button)
        }
    

    Now, modify your setButtonTitles() function to update the titles of the buttons based on the randomPokemons array:

    func setButtonTitles() {
        // Iterate through the buttons and update their titles
        for (index, button) in buttons.enumerated() {
            if index < randomPokemons.count {
                button.setTitle(randomPokemons[index].name.capitalized, for: .normal)
            } else {
                // Handle the case where there are fewer Pokemon names than buttons
                button.setTitle("", for: .normal)
            }
        }
    }