views:

51

answers:

2

I cant wrap my head around this for some reason...

I have a class (Model) with an ivar (value). I want to pass the value to a method and change the value ivar to point to something else. This changes the aValue to point to newString. So, how do I get the model.value to point to newString with out saying model.value = newString?

(void)applicationDidFinishLaunching:(NSNotification *)aNotification {
 Model * model = [[Model alloc] init];//model.value gets set in init
 [self doSomething:model.value];
 NSLog(@"changed?  %@", model.value);
}

- (void)doSomething:(NSString *)aValue
{
 NSString * newString = [[NSString alloc] initWithString:@"new string"];
 aValue = newString;
 NSLog(@"changed? %@", aValue);
}

Also, how do I get this darn code block to work right?

A: 

You need to pass in a pointer to the ivar, and not the ivar itself.

[self doSomething:&model.value];

And create your method like so:

- (void)doSomething:(NSString**)aValue {
    *aValue = @"new string";
}

So when you do

NSString *foo = @"old string";
[self doSomething:&foo];
NSLog(@"foo is: %@", foo);

foo's value is @"new string".

You are accepting the pointer to the object, and making it point to a different object. Normally, the function gets it's own pointer and you assigning a new value to it has no effect outside of the scope that created it.

I'm actually not sure what this is officially called, but I am pretty sure this is how it works. Anyone more well versed in C can likely clarify.

And, of course, this example is easily cleaned by simply returning a value. This trick is useful, but I think in most cases your code will be easier to understand and overall cleaner if you avoid this pattern. So only use it if you have a good reason, like you have a method returning a value, but also want to return more values that may or may not be important that the caller can optionally capture. But if you can simply return a value and assign it, it's probably better that you do.

Squeegy
I updated the method to use (NSString **) andI tried [self doSomething:
joels
Squeegy
+1  A: 

What's wrong with updating the property using model.value=newString? If you really want doSomething: to modify its string parameter, you need to pass a pointer to the variable:

- (void)doSomething:(NSString **)aValue
{
    [*aValue release];

    NSString * newString = [[NSString alloc] initWithString:@"new string"];
    *aValue = newString;
    NSLog(@"changed? %@", *aValue);
}

and call it like this:

[self doSomething:&value];

But this is not very idiomatic. It is probably cleaner to just return a value and let the caller decide how to manage the result:

- (NSString*)doSomething
{
    NSString * newString = [[NSString alloc] initWithString:@"new string"];
    NSLog(@"changed? %@", *aValue);
    return [newString autorelease];
}
gavinb