4

In the Modern Objective-C runtime, you can do something like this:

@interface MyClass : NSObject {
}
@property NSString *stringProperty;
@end

@implementation MyClass
@synthesize stringProperty;
@end

It is my understanding with the modern runtime this will not only synthesize the accessors for my property, but also the instance variable itself, so I could then say in one of this class's methods [stringProperty length]; and it would work just as if I'd declared an instance variable.

I've started using this in all my code now, because, well it's one less thing I have to write over and over again. And I've heard with the clang 2.0 compiler, I'll even be able to skip the @synthesize (but that's another matter). But I've been wondering, what are some of the downsides to doing this? When might I truly need an instance variable in addition to my properties?

I know there are sometimes when I want to keep a variable private and not give access to it externally (but then I usually just declare the property in my private class extension, or I don't create a property for it at all, if I don't need accessors for it).

Are there any times when I wouldn't want to do this?

jbrennan
  • 11,943
  • 14
  • 73
  • 115
  • @joe Yes, if I were to declare the property and synthesize it as above, but I don't explicitly declare an ivar myself, the compiler will still actually create the ivar. So I could do `int len = [self.stringProperty length]` as you'd expect inside the class, AND I can also do `int len = [stringProperty length]` as well, without using the accessor method, just directly using the ivar (which the compiler has synthesized for me, along with setter+getter). It's really fantastic! – jbrennan Dec 08 '10 at 19:34
  • @joe I found out about this from inspecting the stubs XCode4 is now generating for the app delegate. –  Apr 11 '11 at 21:39

5 Answers5

4

One possible reason why it might be advisable to not use synthesized instance variables is they are a bit more of a pain to debug in the current version of Xcode (3.2.5). They don't seem to show up in the live debugger view when running code through GDB, the only way to get at them is through the gdb console like po [0xOBJ_ADDRESS propertyName]. Not exactly as nice as a standard, non-synthesized ivar.

Maybe Xcode 4 fixes this but I don't have enough experience with it to say (and it's still under NDA).

More info on this SO question: Seeing the value of a synthesized property in the Xcode debugger when there is no backing variable

Community
  • 1
  • 1
jbrennan
  • 11,943
  • 14
  • 73
  • 115
  • 2
    +1 This, along with backwards compatibility, are (IMO) the only real reason for keeping declared ivars. They're just easier to debug. – Dave DeLong Dec 07 '10 at 22:58
  • 1
    @neoneye As far as I can tell, yes, as of Xcode 4.0.2 on Snow Leopard this is still the case unfortunately. – jbrennan Jun 03 '11 at 19:22
3

You may want to provide many properties for a single instance variable, e.g., :

  • for accessing an angle value both in degrees and radians
  • for accessing coordinates both in rectangular and in polar systems

In these cases, you don't want to synthesize instance variables (it already exist) nor accessor methods (you want to provide them for doing conversions).

mouviciel
  • 66,855
  • 13
  • 106
  • 140
  • 1
    Sure, but this doesn't really have anything to do with the compiler synthesizing an instance variable. Let's say instead of my `stringProperty` I had instead used a property for `float angleInDegrees`. So this would synthesize an ivar for my angle in degrees, and I could add a second (`readonly`) property that converts it to radians and returns that. Unless I'm missing something, of course. – jbrennan Dec 07 '10 at 21:16
  • The second property doesn't need to be readonly: what if you want to write a value expressed in radians? Just add a `@property float angleInRadians`, don't `@synthesize` it, and provide accessor methods which perform conversion in both directions. – mouviciel Dec 07 '10 at 21:23
1

Anytime you need to make a conversion (unless someone knows a better way) in a class you need to serialize. For example if you have a class that has a numeric value. You cannot serialize an integer so you store it as a NSNumber in the class but the property is a integer type.

Another example is if you code as Apple recommends when working with CoreData. They say you should create a custom class derived from NSManagedObject as the Class for your managed object and use a property for each attribute. Then you would use @dynamic instead of @synthesize and no iVar is needed at all.

Rob
  • 4,149
  • 5
  • 34
  • 48
  • `[coder encodeInteger:someIntVar forKey:@"myIntKey"];` not doing it for you? – jbrennan Dec 07 '10 at 21:13
  • That would be why I put "unless someone knows a better way". I'll remember your code should the need arise. :-) – Rob Dec 07 '10 at 23:13
1

But I've been wondering, what are some of the downsides to doing this? When might I truly need an instance variable in addition to my properties?

Possible reasons:

  • it allows you to change the instance variable in init and dealloc without tripping over subclass overrides or KVO.
  • the app will compile and run in 32 bit mode on Mac OS X. There are still some Intel Macs out there that don't support 64 bit.

I'm not sure how valid the first point really is. There may be other ways around the issues. The second point is game over though if you need to support older Macs.

JeremyP
  • 84,577
  • 15
  • 123
  • 161
  • I have one of those 32-bit older Macs and as far as I can tell my code runs just fine on it (though I haven't written a Mac app, but when I run my iOS code in the Simulator on my 32-bit Mac, it works fine). I should probably investigate further. – jbrennan Dec 08 '10 at 19:37
  • As per the KVO example, what problem would `stringProperty = [someString copy];` cause, even if called from my init method? The compiler also actually creates the ivar for me, so I can access it without calling the setter, which (to my understanding) will not trigger KVO. But maybe I'm mistaken about that. – jbrennan Dec 08 '10 at 19:39
  • OK, I tried it out on my older 32-bit Mac, no dice. You are correct, for Mac apps. Curious that the iOS Simulator allows it, even when running on that same Mac. What a shame they didn't include those enhancements for the older Macs' runtime. – jbrennan Dec 08 '10 at 19:49
  • @jbrennan: I didn't know you can still reference the ivar directly when you synthesize it and don't explicitly declare it. As for the feature working in the simulator, I'm a bit surprised about that too. I just checked the binary of a compiled-for-simulator app and it looks like 32 bit Intel. – JeremyP Dec 09 '10 at 08:52
  • Yep, the binary might still be 32b Intel but I'm guessing the actual Runtime of the Simulator must be different than the one running natively on those Macs. It's curious, but I'm guessing it'll be fixed eventually (or 10.7 just won't run on them, or something). – jbrennan Dec 09 '10 at 16:24
0

One other reason is to avoid shortcuts to direct variable access.

I try to follow the personal coding convention: - object variable: prefix with underscore '_xxx' - property: named without underscore 'xxx'

This ensure that I never write unintentionally something like

xxx = value;

or

[xxx someMessage];

I want to always use the getter/setter.

self.xxx = value;
[self.xxx someMessage];

This is particularly useful when you are using lazy init for object variables...

Jasarien
  • 58,279
  • 31
  • 157
  • 188
Sylvain G.
  • 508
  • 2
  • 9
  • That was my coding style, too. But it made for extra long and tedious property declarations. I bet there is still a way, when having the compiler synthesize the ivar, for it to create it under the name _ivarName for a property called ivarName. I will investigate. – jbrennan Dec 08 '10 at 19:41
  • I just tried it out, and yes it's possible. `@property NSString *myString;` then `@synthesize myString = _myString;` will create the ivar for you, and it will be called `_myString` and your property will still be called `myString`. – jbrennan Dec 08 '10 at 19:54
  • I never tried this to be able to work with GDB. Fine that it's working. Might switch to this behavior. BTW, XCode 4 was demoed with its own mecanism to declare properties, some code that you don't have to write. – Sylvain G. Dec 09 '10 at 10:32