views:

125

answers:

3

I know the title of this question is a bit confusing, but here it goes anyway:

I'm creating an NSString after an if statement but it just doesn't seem to want to retain outside of the statement. My conditional looks like this:

if ([[password stringValue] isEqualToString:@""]) {
    NSString *pwd = [[NSString alloc]initWithString:@"password"];
}
else {
    NSString *pwd = [[NSString alloc]initWithFormat:@"%@", [password stringValue]];
}

... and I call pwd later in the script like this:

NSArray *arguments;
arguments = [NSArray arrayWithObjects: ip, pwd, nil];
[task setArguments: arguments];

But when I do so in this way, the first snippet returns a warning of Unused variable 'pwd' and the latter call ends up in an error of 'pwd' undeclared.

What am I doing wrong here? Thanks in advance. ;)

+12  A: 

Use:

NSString* pwd = nil;
if ([[password stringValue] isEqualToString:@""]) {
    pwd = [[NSString alloc]initWithString:@"password"];
} else {
    pwd = [[NSString alloc]initWithFormat:@"%@", [password stringValue]];
}

The problem is that each block introduces a scope. A variable exists only in the scope in which it is defined (a variable exists from the point of declaration to the end of the scope it is declared). Although the memory pointed to by "pwd" will outlast the if...else block, the pointer named pwd will cease to exist after the if...else block in which it is declared. Declaring the pointer before the block moves pwd up one scope.

Michael Aaron Safyan
Wow, thanks, it worked! Any particular reason why this is necessary? Seems a bit annoying.
esqew
@seanny94, I have added more explanation.
Michael Aaron Safyan
@seanny94, also, although you may find it annoying, it is actually a good thing... it ensures that variables that are no longer relevant are not accidentally used or modified. For example, if you have a loop in which you construct some object and add it to an array... you usually don't want your loop to accidentally use values from the previous iteration. Or, if you do a swap and have temporary variables, you can use braces {} to create a scope, so that your temporaries will no longer exist after the swap.
Michael Aaron Safyan
@seanny94: The scoping rules of Objective-C are identical to C, and many C-derived languages (such as Java) also use them.
eman
A: 

You have declared pwd as a local variable inside the bodies of the if. The variable you refer to later is probably declared outside, and is never set by either assignment. Simply remove NSString * from the assignments.

Marcelo Cantos
+8  A: 

It's not a problem of retaining, but one of scope of your declarations: a declaration within braces has a lexical scope that terminates at the closing brace -- that declaration's just not visible outside of the block! So just move your declaration before the block and have only the initialization within the block, i.e.:

NSString *pwd;
if ([[password stringValue] isEqualToString:@""]) {
    pwd = [[NSString alloc]initWithString:@"password"];
}
else {
    pwd = [[NSString alloc]initWithFormat:@"%@", [password stringValue]];
}
Alex Martelli