How to shorten this code to prevent duplication of code?

107 views Asked by At

I had this question for quite a bit long. I am trying to visualize the 3 doors problem, just for fun and practice with Swift. So I have:

3 doors, and therefore 3 different IBActions & 3 functions for all doors. These function are all exactly the same, however only the number of the doors are different in each code. So I was wondering, can I shorten this code?:

func openSecondChoice(whatDoorIsClickedOn: Int)
    {
        if whatDoorIsClickedOn == 1
        {
            if whatDoorIsClickedOn == doorWithNumber
            {
                UIButtonDoor1.setBackgroundImage( UIImage (named: "doorWithMoney"), for: UIControlState.normal)
            }
            else
            {
                UIButtonDoor1.setBackgroundImage( UIImage (named: "doorWithGoat"), for: UIControlState.normal)
            }
        }
        if whatDoorIsClickedOn == 2
        {
            if whatDoorIsClickedOn == doorWithNumber
            {
                UIButtonDoor2.setBackgroundImage( UIImage (named: "doorWithMoney"), for: UIControlState.normal)
            }
            else
            {
                UIButtonDoor2.setBackgroundImage( UIImage (named: "doorWithGoat"), for: UIControlState.normal)
            }
        }
        if whatDoorIsClickedOn == 3
        {
            if whatDoorIsClickedOn == doorWithNumber
            {
                UIButtonDoor3.setBackgroundImage( UIImage (named: "doorWithMoney"), for: UIControlState.normal)
            }
            else
            {
                UIButtonDoor3.setBackgroundImage( UIImage (named: "doorWithGoat"), for: UIControlState.normal)
            }
        }
    }

Yuk! This code is so ugly! If the user presses on door1 for example, I'm calling the function "openSecondChoise(whatDoorIsClickedOn: 1)". Is there a way to shorten this? Thank you! I do not use classes here, should I use them?

3

There are 3 answers

3
Emil Laine On BEST ANSWER

Usually when you start suffixing your variable names with 1, 2, 3, etc., it's time to use an array instead. This is what arrays are for.

With an array uiButtonDoors that contains your UIButtonDoor1...UIButtonDoor3, your function could look like this:

func openSecondChoice(whatDoorIsClickedOn: Int) {
    let imageName = whatDoorIsClickedOn == doorWithNumber ? "doorWithMoney" : "doorWithGoat"
    uiButtonDoors[whatDoorIsClickedOn - 1].setBackgroundImage(UIImage(named: imageName), for: UIControlState.normal)
}
4
CodingMeSwiftly On
func openSecondChoice(whatDoorIsClickedOn: Int) {
  let imageName = whatDoorIsClickedOn == doorWithNumber ? "doorWithMoney" : "doorWithGoat"
  let image = UIImage(named: imageName)

  let button: UIButton

  switch whatDoorIsClickedOn {
  case 1:
    button = UIButtonDoor1
  case 2:
    button = UIButtonDoor2
  case 3:
    button = UIButtonDoor3
  default:
    fatalError("Cannot be. Switch must be exhaustive, that's why we need to use 'default' for a switch on Int.")
  }

  button.setBackgroundImage(image, for: .normal)
}

For a shorter version check @tuple_cat s answer.

2
par On

Another approach, for fun.

import UIKit

class DoorGame {
    func setupButtons() {
        let buttons = [UIButton(), UIButton(), UIButton()]

        for (index, button) in buttons.enumerated() {
            button.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)
            button.setTitle("\(index)", for: .normal)
        }

        let winningIndex = Int(arc4random_uniform(UInt32(buttons.count)))

        buttons[winningIndex].tag = 1
    }

    @objc func buttonTapped(_ sender: UIButton) {
        let imageName = sender.tag == 1 ? "doorWithMoney" : "doorWithGoat"
        let image = UIImage(named: imageName)

        sender.setBackgroundImage(image, for: .normal)
    }
}