15

I am trying to understand the purpose of the synthesize directive with property name overriding. Say that I have an interface defined as follow:

@interface Dummy ... {
    UILabel *_dummyLabel;
}

@property (retain, nonatomic) UILabel *dummyLabel;

And in the implementation file, I have:

@synthesize dummyLabel = _dummyLabel;

From what i understand, "dummyLabel" is just an alias of the instance variable "_dummyLabel". Is there any difference between self._dummyLabel and self.dummyLabel?

Jacob Relkin
  • 161,348
  • 33
  • 346
  • 320
Thomas
  • 237
  • 1
  • 4
  • 9

5 Answers5

24

Yes. self._dummyLabel is undefined, however _dummyLabel is not.

Dot syntax expands out to simple method invocations, so it's not specific to properties. If you have a method called -(id)someObject, for example in the case of object.someObject, it will be as if you wrote [object someObject];.

self.dummyLabel  //works
self._dummyLabel //does not work
dummyLabel       //does not work
_dummyLabel      //works
[self dummyLabel];  //works
[self _dummyLabel]; //does not work
Jacob Relkin
  • 161,348
  • 33
  • 346
  • 320
  • Thanks for the quick answer. Hm... okay, are [self.dummyLabel setText:@"..."] and [_dummyLabel setText:@"..."] doing the samething? If so, I don't see any big advantage of renaming _dummyLabel to dummyLabel. – Thomas Sep 27 '10 at 10:22
  • 1
    The advantage of having another name for the ivar than for the property is that you can easily see in the code when you are accessing one or the other. – AndersK Nov 15 '10 at 01:06
  • So self.dummyLabel means something like this.getDummyLabel() and simply _dummyLabel means this.dummyLabel if I wanted to talk in java terms? – Asif Apr 28 '16 at 06:36
17

Your understanding is incorrect. dummyLabel is the name of the property, and is not an alias for the instance variable - the instance variable is only called _dummyLabel. So the following holds for an instance of Dummy called myObject:

  • [myObject dummyLabel] works
  • myObject.dummyLabel works
  • [myObject _dummyLabel] fails
  • myObject._dummyLabel fails
  • myObject->dummyLabel fails
  • myObject->_dummyLabel depends on the visibility of the ivar (@public, @private, @protected)
  • [myObject valueForKey: @"dummyLabel"] works
  • [myObject valueForKey: @"_dummyLabel"] depends on the implementation of +accessInstanceVariablesDirectly (i.e. it will work in the default case where +accessInstanceVariablesDirectly returns YES).
  • So, when I want to access an instance variable within a method I could use `_dummyLabel = @"blah"` -- and that would change the value directly, rather than going through a setter? So I could have a read-only property without a setter, but still change it internally by going straight to the ivar? And if I want to use a getter/setter from within a method of the class I'd just use `self.dummyLabel`? Or could I also use `dummyLabel` directly? – Oliver Mason Aug 19 '11 at 12:43
13

The advantage of having another name for the ivar than for the property is that you can easily see in the code when you are accessing one or the other - Andre K

I'm not able to find a 'comment' button so I'm having to post as an 'answer'.

Just wanted to expand on Andre's comment - by knowing when you are using the synthesized properties vs the vanilla variable, you know (especially in case of setters) when a variable is being retained/copied/released automatically thanks to your nice setter, vs being manipulated by hand.

Of course if you are doing things right, you probably don't need the help of a setter to retain/release objects properly! But there can be other scenarios too where referring to your ivars as self.ivar instead of _ivar can be helpful, such as when you are using custom setters/getters instead of the default synthesized ones. Perhaps every time you modify a property, you also want to store it to NSUserDefaults. So you might have some code like this:

@interface SOUserSettings : NSObject {

BOOL _autoLoginOn;

}

@property (nonatomic, assign) BOOL autoLoginOn;

@end

@implementation SOUserSettings

@synthesize autoLoginOn = _autoLoginOn;

- (void)setAutoLoginOn:(BOOL)newAutoLoginOnValue {

   _autoLoginOn = newAutoLoginOnValue;
   [[NSUserDefaults standardUserDefaults] setBool:_autoLoginOn forKey:@"UserPrefAutoLoginOn"];
}

@end

Note: This is just illustrative code, there could be a thousand things wrong with it!

So now, in your code, if you have a line that says _autoLoginOn = YES - you know it's not going to be saved to NSUserDefaults, whereas if you use self.autoLoginOn = YES you know exactly what's going to happen.

The difference between _autoLoginOn and self.autoLoginOn is more than just semantic.

Dev Kanchen
  • 2,332
  • 3
  • 28
  • 40
0

Old post, but I think its important to mention, that it is recommended to access variables via getters and setters (so, with dot notation). Accessing a field directly (_ivar) is strongly recommended only when initializing it.

There is some good Apple's article: https://developer.apple.com/library/ios/#documentation/cocoa/conceptual/ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html

Last paragraph:

You should always access the instance variables directly from within an initialization method because at the time a property is set, the rest of the object may not yet be completely initialized. Even if you don’t provide custom accessor methods or know of any side effects from within your own class, a future subclass may very well override the behavior.

radekEm
  • 4,617
  • 6
  • 32
  • 45
0

I don't see any big advantage of renaming _dummyLabel to dummyLabel

In some ObjC runtimes you have a hard time making instance variables invisible to users of the class. For them sticking some prefix (or suffix) on your instance variables can make it clear (or more clear) that you don't want anyone messing with your variables. However you don't want that gunk on your public functions. This lets you get it off.

It could also be useful if you need to maintain an old interface with one set of names at the same time as a new set of APIs with a new set of names (setLastname vs. setSurname).

Stripes
  • 4,161
  • 2
  • 25
  • 29