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.