Objective C - Pass by value and pass by reference

First of all, sorry for this simple question. But I need to understand what is happening.

I thought the output should be upper case string. But it comes out to be UPPER CASE STRING.

- (void)test
{
     NSString *stringVar = @"UPPER CASE STRING";
     [self changeString:stringVar];
     NSLog(@"value after changed : %@", stringVar);
}

- (void)changeString:(NSString*)string
{
     string = [string lowercaseString];
}

What is happening and how to fix it?

preguntado el 31 de julio de 12 a las 10:07

5 Respuestas

Las [string lowercaseString] la llamada crea un Un nuevo NSString object that you assign to the local variable string. This does not change the value of stringVar afuera de changeString function. The pointer itself is passed by value.

One way to do what you want, is to pass a pointer to a pointer:

-(void) test
{
     NSString *stringVar = @"UPPER CASE STRING";
     [self changeString:&stringVar];
     NSLog(@"value after changed : %@", stringVar);
}

-(void) changeString:(NSString**)string
{
     *string = [*string lowercaseString];
}

Respondido 31 Jul 12, 10:07

Just to make sure, ARC would handle the memory handling even in this case transparently, right? - joachim isaksson

Dear Greg, This means Objective C by default uses pass by value mechanism right? - Charith Nidarsha

@JoachimIsaksson: Yes, ARC handles the memory management correctly (the compiler will warn you if it can't figure out what you are doing). - greg hewgill

@charith: Yes, the semantics for argument passing in Objective-C are the same as in C. - greg hewgill

If you look at the reference to the [NSString lowerCaseString] Método, you can see that it returns a new string, with the lowercase'd characters:

Returns lowercased representation of the receiver.

- (NSString *)lowercaseString

What your code does is simply overwrite the reference to the input string with the output of the lowercaseString call, which has no effect. The best way to solve this issue is for you to return the value yourself, which makes the method easier to understand:

-(void) test
{
     NSString *stringVar = @"UPPER CASE STRING";
     stringVar = [self changeString:stringVar];
     NSLog(@"value after changed : %@", stringVar);
}

-(NSString *) changeString:(NSString*)string
{
     string = [string lowercaseString];
     return string;
}

Necesitas entender eso NSString is immutable so there is no way, other than reassigning the reference, to change a string's contents. You could, however use NSMutableString instead, which can be modified in place.

Respondido el 04 de Septiembre de 14 a las 07:09

I am referring to above given problem and helping you with the mistake.Find my comments

- (void)test
{
     NSString *stringVar = @"UPPER CASE STRING";
     //StringVar is a pointer to integer class.let us assume the address the stringVar be 0x50 and the value it has be 0x100
     //So 0x100 has the string 

     [self changeString:stringVar];
     //above we are calling the method to lowercase and argument is stringVar
     //As the method is called we pass 0x100 in the argument as this is the memory where the value is kept

     NSLog(@"value after changed : %@", stringVar);
    //Our StringVar still points to 0x100 where the value is in upperString
}

- (void)changeString:(NSString*)string
{
     string = [string lowercaseString];
    // Now operation performed on string returns a new value on suppose location 0x200
   //String parameter passed in argument is assigned the new value.But we never pass values as we pass only location under the hood
   //New parameter passed now points to new memory location 0x200

}

---------------------------------------------------------------------------------
With the new solution
-(void) test
{
     NSString *stringVar = @"UPPER CASE STRING";
     //let 0x50 be stringVar memorylocation pointing to 0x100 with above value
     [self changeString:&stringVar];
     //0x50 is passed in argument
     NSLog(@"value after changed : %@", stringVar);
     //On new location stored in address of stringVar it points to new string value
}

-(void) changeString:(NSString**)string
{
     *string = [*string lowercaseString];
     //0x200 is new memory location received.*string gives the 0x100 location and hence the value
   //LHS is assigned to new location .On LHS you find *string which will be assigned 0x200
   //As string with location 0x50 is value 0x200 which will make it to point new      location where lowercase string exist
}

Respondido 20 Oct 16, 15:10

string is a local variable (a pointer to an NSString which is immutable), you're just changing what stringpoints to in the local function, but when you return its value will be thrown away.

What you may want to do is to simply pass the string as a parameter and return the lower case string from the function.

Respondido 31 Jul 12, 11:07

encadenar -(void) changeString:(NSString*)string is local variable, modify method to return value:

-(void) test
{
     NSString *stringVar = @"UPPER CASE STRING";
     stringVar =[self changeString:stringVar];
     NSLog(@"value after changed : %@", stringVar);
}
-(NSString *) changeString:(NSString*)string
{
    return [string lowercaseString];
}

Respondido 31 Jul 12, 11:07

Assigning NSString to a Void method is an error and a Void method doesn't return a value - Sumanth

sorry, my bad, of cource return value is 'NSString*' - mas'an

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.