views:

167

answers:

4

It's a month ago I was reading a line about that. I am not sure, but I think that if I call self.myInstanceVariable then it uses automatically getters/setters, but if I would call directly myInstanceVariable = @"Foo" for example, then I would bypass any getter/setter which would be really, really, reeeaaallly bad. Right/wrong?

EDIT: I tried this in XCode.

The implementation looks like this:

@implementation Test
@synthesize name;

+ (Test*)testWithName:(NSString*)name {
    Test* test = [self alloc];
    test.name = name;
    return [test autorelease];
}

- (void)setName:(NSString*)newName {
    NSLog(@"SETTER CALLED!!");
    if(name != newName) {
     [name release];
     name = [newName retain];
    }
}

- (NSString*)name {
    NSLog(@"GETTER CALLED!!");
    return name;
}

- (void)doWrongThing {
    NSString *x = name;
    NSLog(@"doWrongThing: %@", x);
}
- (void)doRightThing {
    NSString *x = self.name;
    NSLog(@"doRightThing: %@", x);
}

The test code looks like that:

Test *t = [Test testWithName:@"Swanzus Longus"];
//NSLog(@"%@", t.name);
[t doWrongThing];
[t doWrongThing];
[t doWrongThing];

[t doRightThing];

So after launching this code in another method (I just used an existing project ;) ), I received this output in the console:

2009-05-01 19:00:13.435 Demo[5909:20b] SETTER CALLED!!
2009-05-01 20:19:37.948 Demo[6167:20b] doWrongThing: Swanzus Longus
2009-05-01 20:19:37.949 Demo[6167:20b] doWrongThing: Swanzus Longus
2009-05-01 20:19:37.949 Demo[6167:20b] doWrongThing: Swanzus Longus
2009-05-01 20:19:37.950 Demo[6167:20b] GETTER CALLED!!
2009-05-01 20:19:37.965 Demo[6167:20b] doRightThing: Swanzus Longus

Like you see, you MUST use self.instanceVariableName in order to use the getters and setters (or you do the call in brackets, works too).

Confusion Alert: You must only use self if you hack around in a method of the object from which you want to access an instance variable. From the outside, when you call someObjectPointer.someInstanceVariable, it will automatically access the getters and setters (yep, I tried that out too).

Just thought someone would be interested in a little case study ;)

+8  A: 

That is correct. If you directly use the variable, bypassing the getter/setter you could create bugs. The getter/setter may be responsible for retain and/or releasing the object as well as other things. This could result in crashes/memory leaks etc.

If you are aware that you are bypassing the getter/setter and take the right precautions, there is nothing wrong with accessing the variable directly.

Jab
+3  A: 

Jesse has some good insight (+1 to you, sir).

The only circumstance under which I would consider explicitly calling the underlying member variable directly (thus bypassing the getter/setter) is when I have written the getter/setter myself, and know exactly what it is and isn't doing, and 99% of those times is when I'm just initializing the member in my constructor.

Adam McKee
+1  A: 

Yes, the property syntax calls the setter. In almost all cases, this is what you want, since it handles a lot of memory management correctly by default. Also, the property name, ivar name and getter/setter names can also all be different, so you may find cases where it doesn't look like self.myInstanceVar.

Also, just as a side note, you may or may not know this already, but there's no point to synthesizing a property if you're just going to write all the accessor methods anyway.

Chuck
+2  A: 

Just read the documentation

First, this is incorrect

Test* test = [self alloc];

correct is

Test* test = [[self alloc] init];

Second, if you write

@synthesize name;

methods

- (void)setName:(NSString*)newName
- (NSString*)name

will be generated(!! dot-syntax is just syntax-sugar !!) automatically

Third, when you write

myvar.itInstanceVariable

it translates to

[myvar itInstanceVariable]

and

myvar.itInstanceVariable = newValue

translates to

[myvar setItInstanceVariable:newValue]

About your comment, when you declare you property in that way

@property(nonatomic, retain) MyType *myVar;

and write in implementation

@synthesize myVar

it creates two methods

- (MyType*)myVar {
     return myVar;
}

- (void)setMyVar:(MyType*)newVar {
    if (myVar != newVar) {
       [myVar release];
       myVar = [newVar retain];
    }
}

so you don't need to worry about reteaning/releasing

Igor