20

One of the features of the modern (64 bit OS X and iPhone OS) Objective C runtime is the ability for properties to dynamically synthesize ivars without explicitly declaring them in the class:

@interface MyClass : NSObject {
//  NSString *name; unnecessary on modern runtimes
}

@property (retain) NSStrng *name;

@end

@implementation MyClass

@synthesize name;

@end

In quite a bit of my code I use custom getter implementations in order to initialize the properties:

- (NSString *) name {
  if (!name) {
    name = @"Louis";
  }

  return name;
}

The above is incompatible with synthesized ivars since it needs to access a an ivar that is not declared in the header. For various reasons I would like to update a number of my personal frameworks to use synthesized ivars when built on the modern runtimes, the above code needs to be modified to work with synthesized ivars in order to achieve that goal.

While the Objective C 2.0 documentation states that the synthesized accessors on the modern runtime will synthesize the ivar on first use. It does not specify what low level mechanism is used to do this. Is it done by class_getInstanceVariable(), are the restrictions on class_addIvar() loosened, is it an undocumented function int he objective C 2.0 runtime? While I could implement my own side storage for the data backing my properties, I would much rather use the mechanism that synthesized accessors are using.

Ned Batchelder
  • 364,293
  • 75
  • 561
  • 662
Louis Gerbarg
  • 43,356
  • 8
  • 80
  • 90

3 Answers3

20

I went and looked at the documentation again just now, and I think you're misreading it. Synthesized ivars are created at compile time, not at run time.

According to the Objective-C 2.0 documentation:

There are differences in the behavior that depend on the runtime (see also “Runtime Differences”):

For the legacy runtimes, instance variables must already be declared in the @interface block. If an instance variable of the same name and compatible type as the property exists, it is used—otherwise, you get a compiler error.

For the modern runtimes, instance variables are synthesized as needed. If an instance variable of the same name already exists, it is used.

So all you need to do is declare the instance variable you need, and the same code will work on both runtimes...

Community
  • 1
  • 1
Mark Bessey
  • 19,598
  • 4
  • 47
  • 69
  • 2
    After reading through gcc's synthesizer code this in fact what is going on. – Louis Gerbarg Dec 04 '08 at 10:39
  • 1
    One of the improvements in the Xcode 3.2 era compilers (Clang/LLVM and GCC 4.2) is that you can access ivars of that are created to back synthesized variables even if they are not declared in the class, which makes all of this somewhat moot. – Louis Gerbarg Nov 07 '09 at 11:42
0

What you are looking for is @synthesized name, like:

@synthesize name = _name;

...

- (NSString *) name {
    if (!name) {
        _name = @"Louis";
    }

    return _name;
}
Farcaller
  • 3,070
  • 1
  • 27
  • 42
-6

You add properties at run-time with the NSKeyValueCoding Protocol.

[myObject setValue:@"whatever" forKey:@"foo"];
JD Brennan
  • 992
  • 1
  • 10
  • 20
  • 2
    That's incorrect. You can *set* values with key-value coding, but you can't add properties that way. – jlehr Nov 07 '11 at 17:04
  • You absolutely can add new values with NSKeyValueCoding if the class implements that protocol. But you are correct, that this is the wrong answer to this question since ivars are created at compile time, not with NSKeyValueCoding. – JD Brennan Jan 04 '12 at 02:58
  • 1
    Reread the answer. You can't add *properties* via key-value coding. – jlehr Jan 04 '12 at 16:10