Home > other >  For loop error with button creation in swift
For loop error with button creation in swift

Time:06-22

I am creating a memory game in swift where the user can select the amount of cards that are going to be available at the screen. This selection is made at the menu view controller and the data is passed to the game view controller. I use a for loop to create the buttons that represent the cards of the game and add each button to an array.

But, when initiating the game, different numbers of cards appear incorrectly depending on the amount of cards that the player chose (e.g., if 8 cards are selected, 8 cards appear. But when 10 cards are selected, 9 cards appear).

Button creation function:

func createCardButtons(){
    
    let initialPos = Int(screenWidth/50)
    var xPos = Int(screenWidth/20)
    var yPos = Int(screenHeight/20)
    let size = Int(screenWidth/5)
    let cardBack = #imageLiteral(resourceName: "card_back")

    for _ in 0...cardsNum! {
        
        if xPos < Int(screenWidth - size) {
            
            let button = UIButton(frame: CGRect(x: xPos, y: yPos, width: size, height: size))
            button.addTarget(self, action: #selector(cardPressed), for: .touchUpInside)
            button.setImage(cardBack, for: .normal)
            view.addSubview(button)
            
            buttonsArr.append(button)
            
            xPos  = size   initialPos
        } else {
            xPos = Int(screenWidth/20)
            yPos  = size   initialPos
        }
    }
    
    print(buttonsArr)
}

Print message for 8 cards :

[<UIButton: 0x157509950; frame = (18 40; 75 75); opaque = NO; layer = <CALayer: 0x6000029dba60>>, 
 <UIButton: 0x157509c10; frame = (100 40; 75 75); opaque = NO; layer = <CALayer: 0x6000029dae60>>, 
 <UIButton: 0x157509ed0; frame = (182 40; 75 75); opaque = NO; layer = <CALayer: 0x6000029db960>>, 
 <UIButton: 0x15750a190; frame = (264 40; 75 75); opaque = NO; layer = <CALayer: 0x6000029dacc0>>, 
 <UIButton: 0x15750a450; frame = (18 122; 75 75); opaque = NO; layer = <CALayer: 0x6000029dbc20>>, 
 <UIButton: 0x15750a710; frame = (100 122; 75 75); opaque = NO; layer = <CALayer: 0x6000029daca0>>, 
 <UIButton: 0x15750a9d0; frame = (182 122; 75 75); opaque = NO; layer = <CALayer: 0x6000029dbb00>>, 
 <UIButton: 0x15750ac90; frame = (264 122; 75 75); opaque = NO; layer = <CALayer: 0x6000029dbcc0>>]

Print message for 10 cards:

[<UIButton: 0x15851ba30; frame = (18 40; 75 75); opaque = NO; layer = <CALayer: 0x600002057bc0>>, 
 <UIButton: 0x15851bcf0; frame = (100 40; 75 75); opaque = NO; layer = <CALayer: 0x600002043300>>, 
 <UIButton: 0x15851bfb0; frame = (182 40; 75 75); opaque = NO; layer = <CALayer: 0x60000204fba0>>, 
 <UIButton: 0x15851c270; frame = (264 40; 75 75); opaque = NO; layer = <CALayer: 0x60000204a340>>, 
 <UIButton: 0x15851c530; frame = (18 122; 75 75); opaque = NO; layer = <CALayer: 0x60000204a1a0>>, 
 <UIButton: 0x15851c7f0; frame = (100 122; 75 75); opaque = NO; layer = <CALayer: 0x60000206be80>>, 
 <UIButton: 0x15851cab0; frame = (182 122; 75 75); opaque = NO; layer = <CALayer: 0x600002061840>>, 
 <UIButton: 0x15851cd70; frame = (264 122; 75 75); opaque = NO; layer = <CALayer: 0x600002063a40>>, 
 <UIButton: 0x15851d030; frame = (18 204; 75 75); opaque = NO; layer = <CALayer: 0x600002063420>>]

If cardsNum = 8 adds 8 items to the array, why cardsNum = 10 adds only 9?

CodePudding user response:

Because the else branch of your if-else inside your for loop doesn't create and append a UIButton to your array, whenever this branch is called no button is created for that run of the for loop.

You can fix this by updating the yPos at the start of the loop if necessary, then perform the button creation regardless of whether yPos was modified or not. For example:

for _ in 0...cardsNum! {
        
    if xPos >= Int(screenWidth - size) {
        xPos = Int(screenWidth/20)
        yPos  = size   initialPos
    }
        
    let button = UIButton(frame: CGRect(x: xPos, y: yPos, width: size, height: size))
    button.addTarget(self, action: #selector(cardPressed), for: .touchUpInside)
    button.setImage(cardBack, for: .normal)
    view.addSubview(button)
    
    buttonsArr.append(button)
    
    xPos  = size   initialPos
}

Additionally, with the for loop you are using, cardNum = 8 should actually result in 9 UIButtons in the array (and cardNum = 10 with 11).

for _ in 0...cardsNum!

This means run the loop from 0 to cardsNum inclusive, so including 0 and cardsNum. So here your loop will be called cardsNum 1 times.

If you only want it to be run cardsNum times use the half-open range operator:

for _ in 0..<cardsNum!

This means run the loop from 0 up to but not including cardsNum

(See more about the different range operators in Swift here.)

  • Related