Question about @synthesize

When you create a new application from Xcode that embed CoreData you got those lines in the implementation file of the delegate:

@synthesize window=_window;

@synthesize managedObjectContext=__managedObjectContext;

What are the differences between using only a underscore or double it? What's the difference on writing only:

@synthesize window;

A leading underscore is a naming convention helpful to differentiate between instance variables and accessors. For the compiler it is just a common ivar rename.

Consider the difference (non ARC code):

self.date = [NSDate date];  // OK, the setter releases the old value first
date = [NSDate date];       // WRONG, skipping the setter causes a memory leak
_date = [NSDate date];      // WRONG but easier to see it's not a local variable

With ARC variables won't be leaked, but it is still wrong to skip the @property attributes:

@property (copy) string;
// ...
self.string = someString;   // OK, string is copied
string = someString;        // WRONG string is retained but not copied
_string = someString;       // WRONG but hopefully easier to see

Even worst, some APIs like Core Data rely on KVC notifications to perform lazy loading. If you accidentally skip the accessors, your data will come back as nil.

This is the reason you often find @synthesize var=_var, which makes

  • self.var an accessor reference (invoking setters and getters),
  • _var a direct access reference (skipping setters and getters),
  • and var an invalid reference.

Given that @synthesize var=_var is autogenerated by LLVM 4.0 when @synthesize is omitted, you can consider this the default naming convention in Objective-C.

Keep reading for details...


Modern runtime

In Objective-C 2.0 you declare variables like this:

@interface User : NSObject
@property (nonatomic, assign) NSInteger age;
@end
@implementation User {
@synthesize age; // this line can be omitted since LLVM 4.0
@end

which is translated by the compiler as follows:

@interface User : NSObject {
    NSInteger age;
}
@end
@implementation User
-(void)setAge:(NSInteger)newAge {
    age=newAge;
}
-(void)age {
    return age;
}
@end

If you prefer to use the underscore convention just add the following:

@synthesize age=_age;

That's all you need because with the modern runtime, if you do not provide an instance variable, the compiler adds one for you. Here is the code that gets compiled:

@interface User : NSObject {
    NSInteger _age;
}
@end
@implementation User
-(void)setAge:(NSInteger)newAge {
    _age=newAge;
}
-(void)age {
    return _age;
}
@end

What happens if you add both the ivar and the @property? If the variable has the same name and type, the compiler uses it instead generating a new variable. Quoting The Objective-C Programming Language > Declared Properties > Property Implementation Directives:

There are differences in the behavior of accessor synthesis that depend on the runtime:

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

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

Legacy runtime

But if you need to support the legacy runtime you must either provide an instance variable with the same name and compatible type of the property or specify another existing instance variable in the @synthesize statement.

So the legacy code without underscores would be:

@interface User : NSObject {
    NSInteger age;
}
@property (nonatomic, assign) NSInteger age;
@end
@implementation User
@synthesize age;
@end

Or if you prefer the underscore convention:

@interface User : NSObject {
    NSInteger _age;
}
@property (nonatomic, assign) NSInteger age;
@end
@implementation User
@synthesize age = _age;
@end

What is the best way?

Apple discourages the use of underscore in methods, but not on variables!.

Apple on methods: Coding Guidelines for Cocoa: Typographic Conventions:

Avoid the use of the underscore character as a prefix meaning private, especially in methods. Apple reserves the use of this convention. Use by third parties could result in name-space collisions; they might unwittingly override an existing private method with one of their own, with disastrous consequences.

Apple on variables: Declared Properties and Instance Variables

Make sure the name of the instance variable concisely describes the attribute stored. Usually, you should not access instance variables directly, instead you should use accessor methods (you do access instance variables directly in init and dealloc methods). To help to signal this, prefix instance variable names with an underscore (_), for example: @implementation MyClass { BOOL _showsTitle; }

ISO/IEC 9899 7.1.3 Reserved identifiers (aka C99):

  • All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use.
  • All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces.

On top of that, double leading underscore is traditionally reserved for the vendor of the preprocessor / compiler / library. This avoids the case where you use __block somewhere in your code, and Apple introduces that as a new non-standard keyword.

Google Objective-C Style guide:

Variable Names Variables names start with a lowercase and use mixed case to delimit words. Class member variables have trailing underscores. For example: myLocalVariable, myInstanceVariable_. Members used for KVO/KVC bindings may begin with a leading underscore iff use of Objective-C 2.0's @property isn't allowed.

Google's trailing underscore doesn't force you to type one more character before Xcode fires the autocomplete, but you'll realize it is an instance variable slower if the underscore is a suffix.

Leading underscore is also discouraged in C++ (see What are the rules about using an underscore in a C++ identifier?) and Core Data properties (try adding a leading underscore in the model and you'll get "Name must begin with a letter").

Whatever you chose, collisions are unlikely to happen, and if they do, you'll get a warning from the compiler. When in doubt, use the default LLVM way: @synthesize var=_var;


I own an edit of this post to reading A Motivation for ivar decorations by Mark Dalrymple. You may want to check it out.


You can use just

@synthesize window;

if your instance variable is named 'window', however, some people use a naming convention of prefixing all instance variables with underscore, but still prefer to have their getters and setters without the underscore prefix, thats what the 'window=_window' means.

I don't know what double underscore means, but I suspect it's also a matter of a naming convention.