performSelector with time delay does not work in for loop - iPhone

1.1k Views Asked by At

I was hoping someone could help me out. I am writing a simple game, when a user pushes a button an array of numbers corresponding to button numbers is generated then a for loop is used to turn each button on and off in sequence with a time delay. The problem is that all the button in the array turn on and only the last one turns off. It's like the perfomSelector with time delay command only executes at the end of the for loop, does anyone know why?

Here is the code that I am using:

- (IBAction)buttonPushed:(id)sender;
{
    //creat random array of buttons
    [self randomArray];

    //loop through each button in array and turn them on and off
    for (NSString *i in gameArray) 
    {
        int butNum = [i intValue];

        numLit = [[NSNumber alloc] initWithInt:butNum];

        //turn button on
        [self buttonLit];

        //turn button off
        [self performSelector:@selector(buttonUnLit) withObject:nil afterDelay:1.0];

    }

}

- (void)randomArray
{
    //initialize array
    gameArray = [[NSMutableArray alloc] initWithArray:NULL];

    //************* Build random array of numbers *******************
    for (int i = 0; i < level; i++) 
    {
        //generate a number from 0 to 11 at random
        NSInteger num = (arc4random() % 11);

        //add number to array
        [gameArray addObject:[NSString stringWithFormat:@"%i", num]];
    }
    return;

}

- (void)buttonLit
{
    int numLitInt = [numLit intValue];


    if (numLitInt == 0) 
    {
        [button0 setImage:[UIImage imageNamed:@"0(lite).png"] forState:UIControlStateNormal];
        return;
    }else if (numLitInt == 1)
    {
        [button1 setImage:[UIImage imageNamed:@"1(lite).png"] forState:UIControlStateNormal];
        return;
    }else if (numLitInt == 2)
    {
        [button2 setImage:[UIImage imageNamed:@"2(lite).png"] forState:UIControlStateNormal];
        return;
   }else if (numLitInt == 3)
    {
        [button3 setImage:[UIImage imageNamed:@"3(lite).png"] forState:UIControlStateNormal];
        return;
    }else if (numLitInt == 4)
    {
        [button4 setImage:[UIImage imageNamed:@"4(lite).png"] forState:UIControlStateNormal];
        return;
    }else if (numLitInt == 5)
    {
        [button5 setImage:[UIImage imageNamed:@"5(lite).png"] forState:UIControlStateNormal];
        return;
    }else if (numLitInt == 6)
    {
        [button6 setImage:[UIImage imageNamed:@"6(lite).png"] forState:UIControlStateNormal];
        return;
   }else if (numLitInt == 7)
    {
        [button7 setImage:[UIImage imageNamed:@"7(lite).png"] forState:UIControlStateNormal];
        return;
    }else if (numLitInt == 8)
    {
        [button8 setImage:[UIImage imageNamed:@"8(lite).png"] forState:UIControlStateNormal];
        return;
   }else if (numLitInt == 9)
    {
        [button9 setImage:[UIImage imageNamed:@"9(lite).png"] forState:UIControlStateNormal];
        return;
    }else if (numLitInt == 10)
    {
        [button10 setImage:[UIImage imageNamed:@"10(lite).png"] forState:UIControlStateNormal];
        return;
    }else if (numLitInt == 11)
    {
        [button11 setImage:[UIImage imageNamed:@"11(lite).png"] forState:UIControlStateNormal];
        return;
    }

}


- (void)buttonUnLit
{
    int numLitInt = [numLit intValue];


    if (numLitInt == 0) 
    {
        [button0 setImage:[UIImage imageNamed:@"0.png"] forState:UIControlStateNormal];
        return;
    }else if (numLitInt == 1)
    {
        [button1 setImage:[UIImage imageNamed:@"1.png"] forState:UIControlStateNormal];
        return;
    }else if (numLitInt == 2)
    {
        [button2 setImage:[UIImage imageNamed:@"2.png"] forState:UIControlStateNormal];
        return;
    }else if (numLitInt == 3)
    {
        [button3 setImage:[UIImage imageNamed:@"3.png"] forState:UIControlStateNormal];
        return;
    }else if (numLitInt == 4)
    {
        [button4 setImage:[UIImage imageNamed:@"4.png"] forState:UIControlStateNormal];
        return;
    }else if (numLitInt == 5)
    {
        [button5 setImage:[UIImage imageNamed:@"5.png"] forState:UIControlStateNormal];
        return;
    }else if (numLitInt == 6)
    {
        [button6 setImage:[UIImage imageNamed:@"6.png"] forState:UIControlStateNormal];
        return;
    }else if (numLitInt == 7)
    {
        [button7 setImage:[UIImage imageNamed:@"7.png"] forState:UIControlStateNormal];
        return;
    }else if (numLitInt == 8)
    {
        [button8 setImage:[UIImage imageNamed:@"8.png"] forState:UIControlStateNormal];
        return;
    }else if (numLitInt == 9)
    {
        [button9 setImage:[UIImage imageNamed:@"9.png"] forState:UIControlStateNormal];
        return;
    }else if (numLitInt == 10)
    {
        [button10 setImage:[UIImage imageNamed:@"10.png"] forState:UIControlStateNormal];
        return;
    }else if (numLitInt == 11)
    {
        [button11 setImage:[UIImage imageNamed:@"11.png"] forState:UIControlStateNormal];
        return;
    }

}
3

There are 3 best solutions below

0
On

Daniel - Thank you again for your help here is the solution that worked for me.

- (IBAction)buttonPushed:(id)sender;
{
    //creat random array of buttons
    [self randomArray];

    //loop through each button in array and turn them on and off
    for (NSString *i in gameArray) 
    {
        int butNum = [i intValue];

        NSNumber *number = [[NSNumber alloc] initWithInt:butNum];

        //turn button on
        [self buttonLit:(NSNumber*)number];

        //turn button off
        [self performSelector:@selector(buttonUnLit:) withObject:number afterDelay:1.0];

        [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow: 1.0]];

    }

}
3
On

Youre problem is obvious, you are going through the for loop changining the numLit, you want the selectors to be performed in one second, by the time the first selector fires you have already changed numLit to the last number and thats why all of the fires modify the last button...You should fix this by passing in the number to buttonUnlit, that way you arent dependended on the class variable that you keep changing... something like

- (void)buttonUnLit:(NSNumber*)number
{
    int numLitInt = [number intValue];


    if (numLitInt == 0) 
    {
        [button0 setImage:[UIImage imageNamed:@"0.png"] forState:UIControlStateNormal];
        return;
    }else if (numLitInt == 1)
    {
        [button1 setImage:[UIImage imageNamed:@"1.png"] forState:UIControlStateNormal];
        return;
    }else if (numLitInt == 2)
    {
        [button2 setImage:[UIImage imageNamed:@"2.png"] forState:UIControlStateNormal];
        return;
    }else if (numLitInt == 3)
    {
        [button3 setImage:[UIImage imageNamed:@"3.png"] forState:UIControlStateNormal];
        return;
    }else if (numLitInt == 4)
    {
        [button4 setImage:[UIImage imageNamed:@"4.png"] forState:UIControlStateNormal];
        return;
    }else if (numLitInt == 5)
    {
        [button5 setImage:[UIImage imageNamed:@"5.png"] forState:UIControlStateNormal];
        return;
    }else if (numLitInt == 6)
    {
        [button6 setImage:[UIImage imageNamed:@"6.png"] forState:UIControlStateNormal];
        return;
    }else if (numLitInt == 7)
    {
        [button7 setImage:[UIImage imageNamed:@"7.png"] forState:UIControlStateNormal];
        return;
    }else if (numLitInt == 8)
    {
        [button8 setImage:[UIImage imageNamed:@"8.png"] forState:UIControlStateNormal];
        return;
    }else if (numLitInt == 9)
    {
        [button9 setImage:[UIImage imageNamed:@"9.png"] forState:UIControlStateNormal];
        return;
    }else if (numLitInt == 10)
    {
        [button10 setImage:[UIImage imageNamed:@"10.png"] forState:UIControlStateNormal];
        return;
    }else if (numLitInt == 11)
    {
        [button11 setImage:[UIImage imageNamed:@"11.png"] forState:UIControlStateNormal];
        return;
    }

}

and

- (IBAction)buttonPushed:(id)sender;
{
    //creat random array of buttons
    [self randomArray];
     float dalay=1.0f;
    //loop through each button in array and turn them on and off
    for (NSString *i in gameArray) 
    {
        int butNum = [i intValue];

        NSNumber *num = [[NSNumber alloc] initWithInt:butNum];

        //turn button on
        [self buttonLit];

        //turn button off
        [self performSelector:@selector(buttonUnLit) withObject:num afterDelay:delay];
        delay+=0.5f;
       [num release];

    }

}
0
On

Daniel's solution should solve your problem.

Have you considered subclassing a button? Then coding the subclass to know how to light and unlight itself.

This subclass would need very little logic and your code posted in your question would be reduced.
properties
• litFileName
• unlitFileName
methods
-(void)light
-(void)unlight