I have been climbing the learning curve of X-code for about two months now. I understand the purpose of the #property/#synthesize directives, but it seems that it is a bit redundant to always declare the properties in the .h file, and then synthesize them in the .m file.
Why does the compiler need both directives? If they are always used together, isn't one of them technically redundant?
Thanks in advance for any insights on this subject.
John Doner
The #property (...) foo keyword is used inside your class definition.
You don't need to use #synthesize keyword in the implementation file if you provide appropriate getters/setters.
Example:
#property int SomeInt;
---
-(int)SomeInt {
return _someInt;
}
-(void)setSomeInt:(int)newValue {
_someInt = newValue;
}
Or you can use either #synthesize foo to inform the compiler to generate getters/setters for you or #dynamic to inform the compiler that these methods will be available at runtime - both in the implementation file.
There's actually more magic behind properties in Objective-C, read up on them at Apple Reference Library.
It's so that you can split implementation and declaration. Seems pretty neat to me.
Well, you can't use #synthesize in category implementations, so that might be one reason.
Related
I am new to Objective-C and I was going through the code when I came across this:
#implementation ThreadManager
#synthesize bridge = _bridge;
NSMutableDictionary *threads;
Can I write this as:
#implementation ThreadManager {
NSMutableDictionary *_threads;
RCTBridge *_bridge;
}
Also can someone look at the code and please let me know if #synthesize bridge = _bridge; is actually being used? I think it's redundant.
In both cases, these are different things.
#synthesize creates accessors (-bridge and -setBridge:). Declaring an ivar in #implementation does not.
This style of #synthesize is not common today, and generally is unnecessary (as written, it's almost certainly the default for this property) (*). But it isn't replaced by an #implementation ivar. It's replaced by nothing. You just have to declare the #property. That said, it isn't hurting anything. See Declared Properties for details.
(*) I looked up the code you referenced, and I see why they're using #sythesize. bridge is declared in a protocol, not directly in the interface, so it is needed in this case.
threads here is a class variable, shared by all instances of ThreadManager (it's more typical to make these static, but it's not mandatory; in this form it's really just a global, but in practice that's the same thing). This isn't really an "Objective-C thing." It works just like regular C. Your modified code makes it an instance variable, which is different.
Declaring ivars in #implementation is pretty rare in modern ObjC. The only reason I've done it in years is to hold C++ properties in objects that expose pure-ObjC interfaces, or very occasionally to hold a private C-type that I want to manipulate directly (without accessors). The #property syntax is much nicer and more common.
With the current version of Objective-C, what are the official standards and best practices for declaring ivars, using #property and #synthesize? There are a lot of posts and resources on the topic but most of them are fairly antiquated from a year or two ago. I recently learned to only declare ivars in a statement block in the implementation of a class so that the encapsulation principles of OOP aren't broken but is declaring ivars even necessary in this day and age? What would be a possible use case where doing:
#interface MyClass()
#property (nonatomic) NSString* data;
#end
#implementation MyClass{
#private
NSString* _data;
}
#end
is necessary? To further that, is it ever necessary to use #synthesize? My understanding is that using #property will auto-synthesize both the accessor methods as well as the backing ivars. I've done some experimentation and I noticed that when I don't declare NSString* _data', I can still access_data' in my class implementation. Does that mean that declaring ivars come down to a matter of style, up to the discretion of the programmer? Could I condense my code and remove all ivar declarations in the statement blocks in my implementation and just use #property in my private interface? If that's not the case, what are the advantages and disadvantages of explicitly declaring ivars?
Finally, #dynamic. From what I can gather, it's used to say to the compiler, "Hey compiler, don't auto-generate the accessor method and don't worry if you don't find an implementation for it, I'll provide one at runtime". Is that all #dynamic is used for or is there more to it?
I just want to clarify all these things because it seems like there's a lot of different opinions and that there's not necessarily one right answer. Plus as Objective-C grows and progresses, those answers will change so it'll be nice to have a concise and up-to-date guide. Thanks everyone!
(Also if there's anything that I could word better or make clearer, let me know)
EDIT:
In summary, what I'm asking is this:
1) Is declaring ivars with modern Objective-C necessary?
2) Can I achieve the same effects of declaring ivars and corresponding properties by just using #property?
3) What is #dynamic used for?
4) Can I completely forgo the use of #synthesize or is there a good use case for it?
Upvote and down vote as you see fit.
There's a lot to answer here. I'll break it down:
Declaring ivars
As you've correctly noted, modern versions of the compiler will synthesize backing instance variables for declared #properties. The exception to this is on 32-bit Macs, where the modern Objective-C runtime, including non-fragile instance variables, is not available. Assuming your application is not targeting 32-bit OS X, you don't need to explicitly declare the backing ivar for an #property.
If you still want to use an ivar directly, without a corresponding #property (something I consider a bad idea most of the time), you of course must still explicitly declare the ivar.
#dynamic
#dynamic is as you've said meant to tell the compiler "don't synthesize accessors for this property, I'll do it myself at runtime". It's not used all that often. One place it is used is in NSManagedObject subclasses, where if you declare a modeled property in the header, you don't want to compiler to complain that there's no implementation of accessors for that property, nor do you want it to generate accessors itself. NSManagedObject generates accessors for modeled properties at runtime. The story is similar for custom CALayer subclasses.
#synthesize
#synthesize explicitly tells the compiler to synthesize accessor methods, and (on iOS and 64-bit Mac) a corresponding ivar for the specified property. There are three main cases where you still need to use it:
32-bit Mac apps.
If you've written your own custom setter and getter (or just getter for readonly properties). In this case, the compiler won't synthesize accessors because it sees yours. However, it also won't synthesize the backing ivar. So, you must use #synthesize someProperty = _someProperty;, to tell the compiler to synthesize an ivar. It still won't synthesize accessor methods of course. Alternatively, you can explicitly declare a backing ivar. I favor using #synthesize in this case.
If you want to use a different name for the property's backing ivar than the default (property name with an added underscore prefix). This is rare. The main case I can think of for using it is when transitioning existing, older code, that includes direct ivar access and where the ivars are not underscore-prefixed.
Best current practice seems to be to use properties for all ivars placing the property either in the .h file if they are to be exposed and in the .m file in a class extension if local to the class.
No #synthesize is needed unless the ivar needs to be different than the underscore prepended property name.
Yes, #dynamic is as you describe.
Further, it is no longer necessary to declare local instance methods or order such that the method is above the use.
First off, #synthesize is gone for these scenarios: do not have to do it any more.
Secondly, you don't need the private ivar anymore either.
So in essence, you can just do properties.
The way of controlling access is the same idiom that had become popular before MOC dropped: put the property in the public interface as readonly and then make a readwrite version in the private interface (which should be, as you show above, merely the name with open and close parens).
Note also, that many of the things that cluttered up the public interface in the past can now ONLY be in the private interface, so for instance IBOutlets, etc., since the controller is going to be the only thing diddling them.
I never see #dynamic used anywhere except in CoreDate-generated entities.
For someone who first worked with C++ where the dream was always that the header/interface merely show the user of the class what they needed and all other details would be hidden, I think MOC (Modern Objective C) is a dream come true.
BTW, highly recommend the intro session from WWDC Modern Objective C (from 2012) and the one this year was great too.
So I use the #property key in my header file.
If I do that, I should use the #synthesize key in my implementation, right? But I wonder, is there an actual reason I have to do that? I'm just wondering why isn't writing #property in the header just about enough for the to code know my intentions (having the get/set methods automagically generated).
Sure, according to Why we have to synthesize? we write #synthesize to generate the get/set methods. But my question is about why isn't #property in the header just enough for this?
I ask because whenever I write #property in my header, I immediately go to the implementation and write #synthesize. So for me, the only reason #synthesize is used is to complement the #property keyword. Which seems rather redundant, and makes me assume that #synthesize wouldn't exist if it wasn't because it has other uses. What are those other uses?
#synthesize does two things. It generates the getter/setter pair and it creates the iVar for the property.
Of these two things, I think the iVar creation is the key to when I use #synthesize and when I don't. When create properties for members that are not internally stored as iVars, then (obviously) I don't use #synthesize.
The upcoming auto synthesize feature is not going to be of much help. I always name my iVars with a leading '_', and so I will still need to explicitly synthesize them.
See #AndrewMadsen link: it looks like '_' prefix auto synthesize will generate the iVars.
W00t! Needless to say, I'm much more excited about auto synthesize now!!
As it generates the getters and setters for the instance variables, both to use internally and to use from outside your class, the real magic is found in the setter, as it does the following:
- (void)setValue: (id)newValue
{
if (value != newValue)
{
[value release];
value = newValue;
[value retain];
}
}
This is for a #property (nonatomic, retain)...
The real magic is, that each time you set your instance variable (from in- or outside the object itself) you want to make sure, that you own the passed newValue (with retain), release the old value and set the new value.
So it is possible to set the instance Variable multiple times, without having to manually release the old one. Thats only a speed option :-)
When I declare a #property it is obvious that I would like to use it later. For some reasons declaring #property is not enough and I have to tell compiler to #synthetize it in every .m file. Because of this every .m file in my projects starts with #synthetize.
Why they did not do it in a C# way, where just declaration is enough and compiler do the rest?
By making #synthesize optional, you are free to implement your getter and setter methods in any way you choose.
You can find more information in Apple's Declared Properties documentation, particularly the section titled "Property Implementation Directives".
You get standard Accessors almost for free and its possible to roll your own Getters / Setter if necessary.
I have started work at a new company and one of the guidelines I have been told to adhere to by my team lead is to rarely use retain/release and instead rely on properties for memory management. I can see the appeal of keeping the code clear and leaving less room for mistakes but opening up the interfaces like this makes me uncomfortable. Generally speaking the architecture is very good but I have always been pedantic about closing up my classes to the outside world.
Is using properties like this an accepted design methodology in objective-c? Can anyone provide me with links or a clue where my new team may have picked up this strategy?
There is no need to expose properties to the entire world. In your implementation .m file you can add a little category to declare 'private' properties. E.g.
#import "Class.h"
#interface Class ()
#property (nonatomic, strong) NSDate *privateProperty
#end
#implementation Class
#synthesize privateProperty;
...
#end
Nothing in Objective-C is ever really private in strict terms, so I'd say this was good practice — it hides almost all of the retain/release stuff without requiring an ARC-compatible runtime and has the side effect of not requiring you to mention your instance variables in the header at all (though there are other ways to achieve that).
As a historical note, I think this was the first way to move instance variables out of the header — which is something permitted only by the 'new' runtime on iOS and 64bit Intel 10.6+ — so that may be a secondary reason why your team have settled upon it. Unless they've explicitly told you to make your classes transparent, they may actually be completely in agreement with your feeling (and the well accepted object oriented principle) that implementations should be opaque.
You don't have to declare your properties publicly. Using a class category or class extension, you can place your properties within the implementation.
For example:
// in AnObject.h
#interface AnObject : NSObject
#end
// in AnObject.m
#interface AnObject () // () is class extension, (foo) is a class category
#property (retain) NSString *foo;
#end
#implementation AnObject
#synthesize foo;
#end
For more information, see Apple's documentation.