views:

223

answers:

3

I am working through Beginning iPhone Development. In the book is this method:

-(void)playWinSound
{
    NSString *path = [[NSBundle mainBundle] pathForResource:@"win" ofType:@"wav"];
    SystemSoundID soundID;
    AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath:path], &soundID);
    AudioServicesPlaySystemSound (soundID);     
    winLabel.text = @"WIN!";
    [self performSelector:@selector(showButton) withObject:nil afterDelay:1.5];
}

-(IBAction)spin{
    BOOL win = NO;
    int numInRow = 1;
    int lastVal = -1;
    for (int i = 0; i < 5; i++)
    {
        int newValue = random() % [self.column1 count];

        if (newValue == lastVal)
            numInRow++;
        else
            numInRow = 1;

        lastVal = newValue;
        [picker selectRow:newValue inComponent:i animated:YES];
        [picker reloadComponent:i];
        if (numInRow >= 3)
            win = YES;
    }

    button.hidden = YES;
    NSString *path = [[NSBundle mainBundle] pathForResource:@"crunch" ofType:@"wav"];
    SystemSoundID soundID;
    AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath:path], &soundID);
    AudioServicesPlaySystemSound (soundID);

    if (win)
        [self performSelector:@selector(playWinSound) withObject:nil afterDelay:.5];
    else
        [self performSelector:@selector(showButton) withObject:nil afterDelay:.5];

    winLabel.text = @"";
}

When you click the spin button it calls this spin method. If the win is YES, playWinSound is called which changes the value of winLabel to @"Win!". Why is it that if spin results in a win, the text in winLabel changes to @"Win!" and stays that way. Shouldn't the flow return to the spin method which will change winLabel to @""?

A: 

I think what's happening is that by calling the performSelector method, it's got that afterDelay period...so the method is queued up, the winLabel.text = @"" code executes, then after that the playWinSound method fires, changing the label again.

Jonas
+3  A: 

Yes, and the flow does return to the spin method. The trick is in the call which is performing the playWinSound method:

[self performSelector:@selector(playWinSound) withObject:nil afterDelay:.5];

Note the afterDelay portion of the method. This schedules an invocation of playWinSound at the first available time after 0.5 seconds have passed. Specifically, the invocation will take place at the beginning of the first run loop after 0.5 seconds have passed. This method is being called inside an already-running run loop, so the playWinSound cannot possibly execute until after the spin method has returned.

That said, this seems a very odd way to structure the program. I assume they're setting winLabel.text to @"" to make sure that it gets reset back to an empty string unless it's specifically going to become @"Win!", but I would have structured it very differently. Nevertheless, that's why it works.

BJ Homer
+1  A: 

[self performSelector:@selector(playWinSound) withObject:nil afterDelay:.5];

This method queues the action, returns right away and resets the text to "". If it actually waited and then called selector after timeout it would waste resources.

The action is then executed after the timeout and will set the text to "WIN".

Apple reference:

This method sets up a timer to perform the aSelector message on the current thread’s run loop ...

stefanB