It is more of a complain than a question, though maybe someone has some good points on it. So basically if you want an ivar in your Objective-C class have accessor-methods you have to mention it 3 times
SomeClass* _ivar;
#property (nonatomic,retain/assign/copy) SomeClass* ivar;
#synthesize ivar = _ivar;
and maybe 4th time in dealloc method. So wouldn't it be more convenient if the approach would be like Java-style annotations - in one place before the actual ivar declaration, just something like:
#property (nonatomic,retain,synthesize = ivar,dealloc) SomeClass* _ivar;
this also generates accessor methods, and dealloc - telling to dealloc the ivar in dealloc method.
Actually you don't have to declare ivar - they can be synthesized if you just declare property for them. This should synthesize name iVar for you: (not supported in legacy run-times though - so one of the reasons of this seemingly redundant syntax is for backward compatibility with legacy platforms)
#interface MyClass : NSObject
{
}
#property(copy) NSString *name;
#end
...
#synthesize name;
In new XCode version (4.0 probably) you won't need to use #synthesize as well - properties will be synthesized by default.
So as you see objective-c develops to satisfy your wishes :)
Xcode 4 doesn't automatically synthesize properties unfortunately. But with ARC (automatic reference counting) you no longer need to worry about dealloc and instance variables anymore.
Related
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.
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.
Do properties in Objective-C 2.0 require a corresponding instance variable to be declared? For example, I'm used to doing something like this:
MyObject.h
#interface MyObject : NSObject {
NSString *name;
}
#property (nonatomic, retain) NSString *name;
#end
MyObject.m
#implementation
#synthesize name;
#end
However, what if I did this instead:
MyObject.h
#interface MyObject : NSObject {
}
#property (nonatomic, retain) NSString *name;
#end
Is this still valid? And is it in any way different to my previous example?
If you are using the Modern Objective-C Runtime (that's either iOS 3.x or greater, or 64-bit Snow Leopard or greater) then you do not need to define ivars for your properties in cases like this.
When you #synthesize the property, the ivar will in effect be synthesized also for you. This gets around the "fragile-ivar" scenario. You can read more about it on Cocoa with Love
In your interface, you can formally declare an instance variable between the braces, or via #property outside the braces, or both. Either way, they become attributes of the class. The difference is that if you declare #property, then you can implement using #synthesize, which auto-codes your getter/setter for you. The auto-coder setter initializes integers and floats to zero, for example. IF you declare an instance variable, and DO NOT specify a corresponding #property, then you cannot use #synthesize and must write your own getter/setter.
You can always override the auto-coded getter/setter by specifying your own. This is commonly done with the managedObjectContext property which is lazily loaded. Thus, you declare your managedObjectContext as a property, but then also write a -(NSManagedObjectContext *)managedObjectContext method. Recall that a method, which has the same name as an instance variable/property is the "getter" method.
The #property declaration method also allows you other options, such as retain and readonly, which the instance variable declaration method does not. Basically, ivar is the old way, and #property extends it and makes it fancier/easier. You can refer to either using the self. prefix, or not, it doesn't matter as long as the name is unique to that class. Otherwise, if your superclass has the same name of a property as you, then you have to say either like self.name or super.name in order to specify which name you are talking about.
Thus, you will see fewer and fewer people declare ivars between the braces, and instead shift toward just specifying #property, and then doing #synthesize. You cannot do #synthesize in your implementation without a corresponding #property. The Synthesizer only knows what type of attribute it is from the #property specification. The synthesize statement also allows you to rename properties, so that you can refer to a property by one name (shorthand) inside your code, but outside in the .h file use the full name. However, with the really cool autocomplete that XCode now has, this is less of an advantage, but is still there.
Hope this helps clear up all the confusion and misinformation that is floating around out there.
it works both ways but if you don't declare them in the curly braces, you won't see their values in the debugger in xcode.
From the documentation:
In general the behavior of properties is identical on both modern and legacy runtimes (see “Runtime Versions and Platforms” in Objective-C Runtime Programming Guide). There is one key difference: the modern runtime supports instance variable synthesis whereas the legacy runtime does not.
For #synthesize to work in 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. With the modern runtime, if you do not provide an instance variable, the compiler adds one for you.
If you are using XCode 4.4 or later it will generate instance variable synthesizing code for you.
You just have to declare properties like below; it will generate synthesizing code and instance variable declaring code for you.
#property (nonatomic, strong) NSString *name;
it will generate synthesizing code as
#synthesize name = _name;
and you can access instance variable using _name
it is similar to declare
NSString* _name
but if you declare read-only property it like
#property (nonatomic, strong, readonly) NSString *name;
it will generate code
#synthesize name;
or
#synthesize name = name;
So you should access instant variable name with out prefix "_"
any way you can write your own synthesizing code then compiler will generate code for you.
you can write
#synthesize name = _name;
The Objective-C Programming Language: Property Implementation Directives
There are differences in the behavior of accessor synthesis that depend on the runtime (see also “Runtime Difference”):
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.
For the modern runtimes (see “Runtime Versions and Platforms” in Objective-C Runtime Programming Guide), instance variables are synthesized as needed. If an instance variable of the same name already exists, it is used.