Pregunta

I have this piece of code which plays my mp3 files on my iphone and it works:

if(i == 1) { 
  NSString *url = [[NSBundle mainBundle]pathForResource:@"fart" ofType:@"mp3"];
  player = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:url] error:NULL];
  [player play];
} else if(i==2) {
  NSString *url = [[NSBundle mainBundle]pathForResource:@"fart6" ofType:@"mp3"];
  player = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:url] error:NULL];
  [player play];  
} else {
  NSString *url = [[NSBundle mainBundle]pathForResource:@"fart7" ofType:@"mp3"];
  player = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:url] error:NULL];
  [player play];
}

The only lines that are changing is the NSString *url. When I try to do the below to clean up my code, I get the error of "use of undeclared identifier 'url'".

if(i == 1) { 
  NSString *url = [[NSBundle mainBundle]pathForResource:@"fart" ofType:@"mp3"];      
} else if(i==2) {
  NSString *url = [[NSBundle mainBundle]pathForResource:@"fart6" ofType:@"mp3"];        
} else {
  NSString *url = [[NSBundle mainBundle]pathForResource:@"fart7" ofType:@"mp3"];      
}

player = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:url] error:NULL];
[player play];

Why does NSURL not understand that the NSString *url is set from the above if-else statements?

¿Fue útil?

Solución

"The scope the variables is limited to the block they are declared".

Declare url outside before the if-else block. You can still optimize your code to be like this.

NSString *fileName = @"";
if (i == 1) fileName =  @"fart";
else if (i == 2) fileName =  @"fart6";
else fileName =  @"fart7"; 

NSString *path = [[NSBundle mainBundle]pathForResource:fileName ofType:@"mp3"];
NSURL *url = [NSURL fileURLWithPath:path];
player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:NULL];
[player play];

Otros consejos

The scope of the declaration of the url variable starts at the point of declaration (when you write NSURL *url) and ends at the end of the enclosing block (at the }). Each one of those declarations of url is in a block (between { and }), but your attempted use of the declaration is outside any of the blocks that contain a declaration. So, by the time you try to use it, there is no longer a url identifier declared within the scope.

To fix it, move the declaration out of the blocks, then assign to the variable from within the blocks:

NSString *url = nil;
if(i == 1) { 
  url = …;
} else if(i==2) {
  url = …;
} else {
  url = …;
}

player = [[AVAudioPlayer alloc]
    initWithContentsOfURL:[NSURL fileURLWithPath:url] error:NULL];
[player play];

Alternatively:

NSString *url = nil;
switch (i) {
case 1: url = …; break;
case 2: url = …; break;
default: url = …; break;
}

or even:

NSString *url = (1 == i)? val1 : (2 == i)? val2 : valDefault;

In Objective-C (and other C-bases languages I know), each block has it's own scope so if you declare a variable in that scope, it will not be shared with the containing block but variables from containing block can be seen from the contained block.

A bit vague explanation but here's what you need to do:

NSString *url;
if(i == 1) { 
  url = [[NSBundle mainBundle]pathForResource:@"fart" ofType:@"mp3"];      
} else if(i==2) {
  url = [[NSBundle mainBundle]pathForResource:@"fart6" ofType:@"mp3"];        
} else {
  url = [[NSBundle mainBundle]pathForResource:@"fart7" ofType:@"mp3"];      
}

player = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:url] error:NULL];
[player play];
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top