This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Synthesized property and variable with underscore prefix: what does this mean?
The usage of Objective-C properties has always felt awkward to me. It's one of the "I know how to use them, but I'm not always sure why I'm using them." kind of things and recently I've been seeing a lot of this:
// in .h file
#interface MyObject : NSObject
{
id _coolIvar;
}
#property (assign) id coolIvar;
#end
// in .m file
#implementation
#synthesize coolIvar = _coolIvar;// <- whats the point of that.
#end
So what is the point of declaring an ivar with an underscore and then using #synthesize to access it, Opposed to just declaring the #property with the same name as the ivar?
Side Question:
I've noticed that this convention has been becoming increasingly more popular since blocks started becoming the preferred approach for async callbacks opposed to the target/selector approach. Is that a coincidence or does the above #property declaration convention play nicer with block scopes?
It's preference.
It's also my preference to not declare the variables twice and just let them be synthesized like:
// in .h file
#interface MyObject : NSObject
#property (assign) id coolIvar;
#end
// in .m file
#implementation
#synthesize coolIvar = _coolIvar;
#end
The two reasons I like to use the _ prefix is
I know when I am going through an accessor and when I am accessing the variable straight.
If it makes sense for me to call an ivar address it is more than likely that inside a method a similar variable would also be logically called address. If my ivar does not have an _ prefix then my local address will mask the ivar address.
I also like how xcode will autocomplete vaiables starting with an _ when you start typing your #synthesize myVar = _...
NB
You may run into the odd name clash (I have only once) but the warning that the complier gives you makes it a pretty easy spot and simply changing the name is a quick win.
#isaac touched on not declaring ivars so that they are not publicly advertised but does not explain how/why. Basically you can declare #property's in a class extension to still give you the benefits of the #synthesized getter/setter but without making your public API look ugly.
Your previous example would look like this (if you wanted coolIvar to not be publicaly advertised):
// in .h file
#interface MyObject : NSObject
#end
// in .m file
#interface MyObject () <-- Like a category but with no name
#property (assign) id coolIvar;
#end
#implementation
#synthesize coolIvar = _coolIvar;
#end
I use the _ivar construct to make sure that I don't access the ivar directly (by mistake) when I really intend to go through the accessors.
With the modern runtime (iPhone applications and 64-bit programs on Mac OS X v10.5 and later) the ivar declaration is no longer required. So your code is reduced to:
// in .h file
#interface MyObject : NSObject
#property (assign) id coolIvar;
#end
// in .m file
#implementation
#synthesize coolIvar = _coolIvar;
#end
Per #Monolo's answer, the _ivar is a good failsafe to make sure you don't inadvertently access the ivar directly. Remember, the #property and #synthesize is there to replace boilerplate code - without it you'd have to code getter and setter accessors.
There are a couple benefits to differentiating ivars from property accessors.
One is described by Monolo - it prevents mistakingly accessing an ivar when what you intended to access was a property.
Another is that in theory it guards against collisions - cases where you might name an ivar identically to another ivar that's beyond your implementation (ie, a superclass ivar name).
There are different thoughts on best practices, but lately I've read in several places I consider reliable that the best practice is actually to no longer to declare ivars at all in your interfaces (ivars are created implicitly via the property declaration).
Some people don't like "implicit" - but there are material benefits: Not declaring them avoids advertising ivars that aren't really public. It also goes even further in avoiding collisions - because in theory when a property is synthesized and the ivar generated, it will do so without introducing a convention that may itself collide with a private ivar naming convention (as may be the case with preceding or trailing underscore).
Preference. Some people like to prefix instance variables with a underscore (so one can easily tell if one is referencing a ivar, or a variable in a more local scope), and some don't.
Related
I am learning Objective-C and was just curious. I can create an object of a NSString in these places, and please provide any others. To me they all do the same thing. I don't know what is the difference is between them. Where is it stored? From where can I access it? What are the advantages?
1)
// .h
#interface ...
#property (strong,nonatomic) NSString *text;
#end
2)
// .h
#interface ... {
NSString *text
}
#end
3)
// .m
#interface ... ()
#property (strong,nonatomic) NSString *text;
#end
First and foremost, my answer is based on the latest Clang compiler, older versions worked slightly different.
So, you're not creating an object in neither. You're not even declaring an object in two of them.
In the first case, you're actually telling the compiler that you need to expose a property called text of type NSString. What the compiler does, is declaring an instance variable for you _text (which you can access without a problem by the way) and the methods needed to get and set that instance variable. As you can see the storage is still internal, you just have getters and setters set for you.
In the second case you're actually declaring an instance variable (ivar) yourself, just as the compiler does with _text. It's accustom to prefix it with _. The storage is still internal. On top of that, you can't access your ivar from outside, since it has no getter or setter and the implicit declaration is #private.
In the third case, you create an anonymous category (thus the empty parentheses) which adds a property to your class. Storage for this is a little bit harder/longer to explain, if you are curious about it, you can search up the Apple docs, see what a category is and so on. You can only access your property from within your class in this case, which makes it somehow redundant (the getters and setters), you could have declared it as an ivar.
You can also declare your ivars like this:
#interface GenericViewController : UIViewController{
NSString * text;
}
#end
#implementation GenericViewController{
NSString * text;
}
#end
Both of the above have local storage and private visibility (can't be accessed from outside). The difference between the two is that instance variables declared in the implementation are implicitly hidden and the visibility cannot be changed with #public, #protected and #private. If you use those directives you won't get compiler errors but are ignored.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
iOS: must every iVar really be property?
I just read a book that said that modern convention is not to declare any ivars at all in your .h file between curly braces, and instead to make everything properties.
I want to make sure this is true even in trivial cases. I am making a class where there is a BOOL named "recording" which says whether the device is currently recording some video. This isn't something that other classes need, and my incline is to just put it as a BOOL in the header then refer to it in the .m file in the 2 spots where it is needed.
However, I also want to do things the accepted, right way. But I don't see why I make it a public property?
What you read is wrong, plain and simple.
Modern convention is to skip ivars when there is a corresponding property that can synthesize them. Additionally, with recent versions of LLVM it is possible to move your ivars to your implementation file (as #DrummerB has already mentioned) so that the header contains no ivars. That's considered good practice because it doesn't expose internal workings of the class.
But have no ivars at all and a property for everything that was an ivar? Nope, not normal Objective-C.
Your book is right (and wrong). Don't declare ivars in your headers anymore. That's only supported for compatibility reasons. But also don't declare properties for private variables.
If you want do declare a private ivar that other classes don't need to use, declare them in your implementation file:
// MyClass.m
#implementation {
BOOL recording;
}
// methods
#end
I recommend to not use ivar at all. Instead you can create a class extension in which you will declare properties that has to be hidden:
#interface MyClass ()
#property (nonatomic, assign) BOOL recording;
#end
You could use something like
#interface G4AppDelegate ()
#property (nonatomic, assign) BOOL recording;
#end
To make an "internal" property.
Or as the other answer states use an iVar in your implementation
Some books explain that you should only use getter and setter to access your ivar, even if they are private. This is a little too psychotique to me.
Before clang, u should have to create category on class and use synthesizer to make ur ivar private. like this:
#interface AppDelegate ()
#property(nonatomic, assign)int aValue;
#end
// + #implement AppDelegate
// #synthetise aValue;
that could be annoying since sometime u need some simple ivar, without any getter/setter control. And u're adding code where there is no need.
Now with clang you can put ur ivar directly on implementation file like this in ur code:
#interface AppDelegate (){
int _aValue;
}
#end
And u're hiding private ivar out of the scope the header.
Note, u can't compile this with gcc.
When you declare a #property and #synthesize it, it is considered good practice to use:
#synthesize myProperty = _myProperty;
I've noticed that Xcode will autocomplete the ivar name _myProperty for you, even though it hasn't yet been used in the source code.
Is this because the ivar #synthesize creates automatically defaults to the name _myProperty? Or merely because Xcode supports this common convention with an autocompletion for it?
Thanks.
EDIT: I'm not looking for reasons why this is good practice; I'm already aware of those and have used this convention for a while. I want to understand the internals, thus am asking whether this is a hard-coded auto-completion rule to satisfy a convention, or whether it's standard auto-completion and in fact the Objective-C specification dictates that an ivar generated by #synthesize must have the form _myProperty, thus after behind the scenes generation of the ivar, auto-completion is aware of its existence. Thanks!
I think the autocompletion is an IDE convenience rather than a result of the runtime. My logic for this is that the following appears to be valid:
#interface SomeClass()
#property (nonatomic, assign) int unpublishedInstanceVariable;
#end
#implementation SomeClass
#synthesize unpublishedInstanceVariable;
- (void)someMethod
{
unpublishedInstanceVariable = 3; // not calling the setter
}
#end
hard-coded auto-completion rule to satisfy the convention
If you don't specify an iVar name explicitly, it will be called myProperty. The autocomplete doesn't have anything to do with the compiler, it's just Xcode being extra helpful.
As of Xcode 4.4, there is a new twist to the tail (sic).
We are now allowed to skip the #synthesize altogether. In this case, the compiler automatically generates the #synthesize foo = _foo; declaration for us, with the instance variable name prefixed with an underscore.
#interface Foo : NSObject
#property (nonatomic, copy) NSString *foo;
#end
#implementation Foo
- (void)bar {
NSLog(#"%#", _foo); // this Works!
}
#end
However, if we do have an explicit #synthesize statement but do not specify the name of the instance variable, then the default name of the instance variable is the same as that of the property i.e. not prefixed with an underscore, in which case #Tommy's answer still holds.
It'd be great if someone could point out the links to official Apple Docs that document this behaviour.
Update
My findings were spot on. This behaviour (of #synthesize being the default, and creating a backing underscore prefixed instance variable in the absence of an explicit synthesize etc.) was publicly announced in WWDC 2012 Session 405 - Modern Objective-C.
wrt this part of your question:
whether ... in fact the Objective-C
specification dictates that an ivar generated by #synthesize must have
the form _myProperty,
You can name your ivar anything you want. From the docs:
You can use the form property=ivar to indicate that a particular
instance variable should be used for the property, for example:
#synthesize firstName, lastName, age=yearsOld;
This specifies that the accessor methods for firstName, lastName, and age should be
synthesized and that the property age is represented by the instance
variable yearsOld.
Also,
The #synthesize directive also synthesizes an appropriate instance variable if it is not otherwise declared.
I always thought that one cannot declare an object property in a category.
Until my partner did it in our app's code, and it seemed to work.
I went on a SO and Google binge to try to explain to him that no, Objective-C categories can only be used to add methods, not properties. I found questions such as:
Setting New Property In Category Interface Implementation (look at the accepted answer)
Can I add a property for a method not in my category?
But then I found this link on Apple's site that contains the following about the #property declaration:
A property declaration begins with the
keyword #property. #property can
appear anywhere in the method
declaration list found in the
#interface of a class. #property can
also appear in the declaration of a
protocol or category. (emphasis added)
I know that this doesn't work:
#interface MyClass ()
NSInteger foobar;
- (void) someCategorizedMethod;
#end
But this compiles:
#interface MyClass ()
#property NSInteger foobar;
- (void) someCategorizedMethod;
#end
My question is (a) what's the best practice here? and (b) is this something that is new to Objective-C 2.0, and instead of using a "real" iVar, it simply uses associative storage behind the scenes to make this work?
You have always been able to declare an #property in a category. What you couldn't do -- and still can't -- is declare storage for the property in the category, neither as an instance variable nor via `#synthesize.
However....
#interface MyClass () is not a category. It is a class extension and has a distinctly more specific role than a category.
Namely, a class extension can be used to extend a class's #interface, and this includes #properties that can be #synthesized (including synthesizing storage in the modern runtime).
Foo.h:
#interface Foo
#end
Foo.m:
#interface Foo()
#property int x;
#end
#implementation Foo
#synthesize x; // synthesizes methods & storage
#end
it simply uses associative storage
behind the scenes to make this work?
Nope -- it is a real instance variable. The modern runtime fixes the fragile base class problem.
#interface MyClass ()
NSInteger foobar;
- (void) someCategorizedMethod;
#end
The above doesn't work (as expected) because foobar is, effectively, a global variable.
If you change it to:
#interface MyClass () {
NSInteger foobar;
}
- (void) someCategorizedMethod;
#end
Then it'll work with the latest release of the llvm compiler (with the right flags, as #Joshua indicated in a comment).
Generally speaking, properties are nothing different from other methods. As long as the ivar used is available in the ordinary class, there is no problem at all. It's just syntactic sugar.
Things start to get more difficult if also the ivar is automatically created, as is possible in some configurations.
The main point here is that declaration of the ivar is independent from the property.
Assotiative storage is the solution.
Have a look at this post.
One of the things I've been struggling with, whilst breaking into Objective-C programming, is understanding how to manipulate properties. I'm perhaps out of my comfort zone using a proper coding language as opposed to scripting languages that I'm used to, so the declaring things in header files and implementation files is confusing me somewhat.
Let's say I have a String. I wish to add some text into that string. What do I declare in the header file and what do I do in the implementation file to allow this to work properly, and what are #property and #synthesize?
In the bad old days before Objective-C 2.0, it was common to write getters and setters for your instance variables e.g.
#interface Foo : NSObject
{
#private
id foo;
}
-(void) setFoo: (id) newFoo;
-(id) foo;
#end
#implementation Foo
// need dealloc to release foo too.
-(void) setFoo: (id) newFoo
{
[newFoo retain];
[foo release];
foo = newFoo;
}
-(id) foo
{
return foo;
}
#end
And that's just in the single threaded environment. There was even more stuff needed for multithreaded apps.
Properties provide a neat shorthand for the above. The #property replaces both of the declarations in the interface as well as giving the caller better hints about the semantics of the getter and setter. It also allows you to #synthesize the accessors so the compiler will generate the code for them automatically (you don't have to #synthesize them, you can provide your own implementations if you want). All of the above can be replaced by
#interface Foo : NSObject
{
#private
id foo;
}
#property (nonatomic, retain) id foo;
#end
#implementation Foo
// need dealloc to release foo too.
#synthesize foo;
#end
That saves quite a lot of typing but also you can see from the interface that setFoo: will retain its new value and that the property is not safe to use (to set or get) in a multithreaded environment (without some other locking mechanism).
#property - declares a property with access and memory modifiers. Properties can be readonly or readwrite, nonatomic or atomic (thread safety), assign/retain/copy managed. Actually, you can declare simple getter and setter methods like we did in the Tiger era, but declaring a #property will help you to identify all aspects of the property at any time without checking the implementation.
#synthesize - simplifies the job if you need a simple property without any complex job in getter and setter. It defines a default implementation according to the definition of #property.
At last, your questions about string. Properties won't help here if you are looking for something simple, let's say myObj.string += "abc". It's not Objective-C style and with or without property you will do something like myObj.string = [[myObj string] stringByAppendingString:#"abc"] or [[myObj string] appendString:#"abc"] depending on mutable/immutable nature of the string object.
As a bottom line: it's quite a big topic to explain everything in a single post. I'd recommend you to read Apple documentation and maybe purchase a book about Objective-C. Aaron Hillegass wrote one - a good start for any Objective-C and Mac OS X beginner.