Should I declare variables in interface or using property in objective-c arc?
The most modern way1:
- whenever possible, declare properties
- don't declare iVars separately 2
- don't @synthesize 3
- locate as few properties as possible in you .h file 4
- locate as many properties as possible in a class extension in your .m file 5
1 As of Xcode 4.5.2. Most of this applies back to 4.4, some of it won't compile on 4.2 (the last version available under Snow Leopard). This is preprocessor stuff, so it is all compatible back at least to iOS5 (I haven't tested on iOS4 but that should also be OK).
2 There is no point in declaring an iVar as well as a property. I am sure there are a few obscure cases where you would want to declare iVars instead of properties but I can't think of any.
3 Xcode will create an iVar with the same name as the property, preceded by an _underscore. If you (rarely) need some other kind of behaviour, you can manually @synthesize property = someOtherName
. @vikingosegundo links us to this article on dynamic ivars, which is a use case for @synthesize
. @RobNapier comments that you do need to @synthesize iVar = _iVar
(bizarrely) if you are creating your own getters (readonly) and setters (read/write) for a property, as in this case the preprocessor will not generate the iVar for you.
4 The general rule with your interface: keep it as empty as possible. You don't actually need to declare your methods now at all, if they are for private use. If you can get the code to work without an interface declaration, that's the way to go.
5 This is an @interface block in your .m file, placed above your @implementation:
#TestClass.m
@interface TestClass()
//private property declarations here
@end
@implementation TestClass
...
In Objective-C, when should I use property and when should I use instance variable?
Use properties everywhere. Don't even declare instance variables, but synthesize them like this: @synthesize myProperty = _myProperty
in order to differentiate them from property names. Properties are good way to cope with memory management as well. The only place you must use the synthesized instance variable is in the dealloc
method.
The advantages of the properties are a lot:
- The accessor methods define how will you get and set the value of your instance variable.
- You can customize the accessor methods (for example to lazy instantiate an ivar or do something when a setting a new value like setNeedsDisplay
.
- You don't cope with memory management when setting a new value - the setter takes care for releasing/retaining (depending how have you declared the property - retain
/copy
/assign
/strong
.
- Some multithreading stuff with the atomic
/nonatomic
attributes
- You can take advantage of the KVO
, when using properties
- And least, but not last - don't worry about performance issues if you have concernes that every time a getter or a setter is called...
Why declare the variables of public properties on the interface with the property declarations?
This was the usual way in a day when you had to synthesize
the properties manually before auto-synthesizing was introduced.
When to use instance variables and when to use properties
can you stop creating instance variables altogether
No, you can't (in a sense). What you can do is stop declaring them if you have properties. If you synthesize a property and you haven't declared the instvar, it will get declared for you, so you are creating an instance variable, just not explicitly.
do they still serve a purpose where properties would be inappropriate?
It used to be the advice to create properties for everything because having synthesized properties does almost all of the retains and releases for you. However, with ARC that reason for using properties to wrap the memory management has gone away. The advice now (for ARC) is, I believe, use properties to declare your external interface, but use direct instance variables where the variable is part of the object's internal state.
That's a good reason to adopt ARC: properties revert to their true purpose only of being part of the class's API and it's no longer necessary to use them as a hacky way to hide memory management work.
Edit
One more thing: you can now declare instance variables in the @implementation
so there is now no need to leak any implementation details in the @interface
. i.e.
@implementation MyClass
{
NSString* myString;
}
// method definitions
@end
And I'm pretty sure it works in categories too. - see comment below
Proper way to use instance variables/property/synthetize with ARC
For simple properties, you don't need the instance variable declaration or the @synthesize
. The clang compiler will generate both for you by default. So you could write this in the header:
@interface SomeClass : NSObject
@property (nonatomic, copy) NSString *someString;
@end
And the implementation:
@implementation SomeClass
- (void)someMethod {
self.someString = @"Foobar";
}
@end
Avoid direct instance variable access unless you are in the -init
method or overriding the setter. Everywhere else you should use the dot syntax (self.someString
). If you do need access to the instance variable, the default synthesize will create an underscore-prefixed ivar, e.g. _someString
.
Note that for classes with mutable versions like NSString
/NSMutableString
and NSArray
/NSMutableArray
the standard practice is to use a copy
property. If you use strong
on a string or array, the caller might pass in a mutable version and then mutate it from under you, causing hard-to-find bugs.
In arc what happens when you don't synthesize
A couple of observations, much of which is probably clear by this point based upon the feedback of others:
You synthesize properties, not instance variables, and in your example, you showed us an example of an instance variable, not a property.
Your question might imply some assumed connection between synthesizing and the ability to do
retain
/release
, but there is no such connection. The ability to doretain
andrelease
is a function of whether you are using ARC or not. It has nothing to do with synthesizing properties.As others have observed, explicitly declared instance variables, such as your example, are
strong
references, by default. So, in your example,_pieces
is astrong
reference.Yes, when your
SomeClass
object is deallocated, it will remove itsstrong
reference to the_pieces
object. Obviously, if that's the last strong reference to the object pointed to by_pieces
it will be deallocated and any otherweak
references you have to it elsewhere will be set tonil
. For a more complete discussion on the memory management, see Apple's Advanced Memory Management Programming Guide and Transitioning to ARC.You asked "If all other objects that have retained
_pieces
release it, will it benil
when I attempt to access it?" Obviously that would be true if_pieces
was aweak
reference, but given that it's implicitly astrong
reference inSomeClass
, no, that is not the case.If you wanted to make
pieces
a declared property, the syntax would be
@property (nonatomic, strong) NSMutableArray* pieces;
The designation ofstrong
vs.weak
(or whatever) dictates the memory management of the property.If you declare a property, you not only no longer have to explicitly define the instance variable, but rather it is now advised that you really should not do so (because when it's synthesized, the compiler will create the ivar for you). But, if you happen to have an explicitly declared instance variable of the right name for your property, the compiler will use that for the property. But that's not only unnecessary, but also inadvisable (because if you mistype the name of the instance variable, you may unwittingly end up with two instance variables). Just let the compiler synthesize your instance variables for your properties and this potential ambiguity goes away.
The name of the instance variable that will be synthesized for a property is governed by the syntax of the property implementation directive, i.e. the
@synthesize
statement. Thus, if you have a@synthesize
statement for yourpieces
property of the form:@synthesize pieces;
then the instance variable will be calledpieces
. But if you use the preferred@synthesize
syntax of:@synthesize pieces = _pieces;
then the instance variable name will have the preceeding underscore (which is, by convention, preferred, to avoid ambiguity in your code between properties and instance variables). And, as of Xcode 4.4, if you omit the@synthesize
statement for a@property
, it will implicitly synthesize it for you with the latter syntax, i.e. the instance variable will bear the leading underscore).
Why we need property outlet and variable in iOS?
If you don't need to access the outlet from another class, you don't need to make it a property. You can make it an instance variable in your @implementation
:
@implementation ViewController {
IBOutlet UIView *someView;
}
...
Some people don't like using plain instance variables and prefer to always use properties, even for private data. It is particularly useful to use properties instead of raw instance variables if you are not using ARC, because you can rely on property setters to retain and release their objects. If you are using ARC, this is not an issue.
If you want to use a property but you don't want to declare the property in your @interface
, you can put a class extension at the top of your .m
file (above your @implementation
), and put the property there:
@interface ViewController () {
@property (nonatomic, strong) IBOutlet UIView *someview;
@end
@implementation ViewController
...
Difference in declarations
Xcode automatically makes them @properties when you command drag them
from storyboard
That's not true, if you want to create class members that are not properties form xib/storyboard, then drag then command drag into the {}
section of your .h file and in this way they won't be declared as properties.
@interface QuickViewControllViewController : UIViewController<UIScrollViewDelegate>{
// drag here the line from xib/storyboard for instance members and not properties
}
Now, properties are used when you want to access the members outside your class like instance.property
and also for every property declared the system will automatically generate setters and getters which won't happen for the other kind of class members.
So in your case if you want to have only class members that are visible inside your class you can use your posted code and in my opinion it's better not to use properties if you are having class members visible only in one class.
As a note, you can also declare private properties for this case but is kind of useless.
Why must I define variables twice in the Header file?
What you're seeing was required in earlier versions of Objective-C,
but isn't any more.In the first versions of Objective-C used by NeXT up until the new
runtime was introduced (with Objective-C 2.0 on Mac OS X), all
instance variables had to be declared as part of the class's structure
in its@interface
. The reason was that if you subclassed a class,
the compiler needed to know the instance variable layout of the class
so it could see at what offset to put the subclass's instance
variables.When properties were introduced, synthesized properties had to be
"backed" by an instance variable in the class's structure. Therefore
you had to declare both an instance variable and the property.All of the above is no longer true. Newer Objective-C is less fragile
in the way it looks up instance variable offsets, which has meant a
few changes:
- not all instance variables need to be in the
@interface
. They can now be defined in the@implementation
: though not in categories due
to the possibilities of clashing and other issues.- instance variables for synthesized properties can be inferred and created based on the property definition.
- you can programmatically add instance variables to classes you're creating at runtime (only before you've registered the class as
available to the system).
So, to reiterate, you only needed to declare both the instance
variable and a synthesized property in older versions of the
Objective-C language. What you're seeing is redundant and should not
be considered a "best practice".
[Source]
Related Topics
How to Get the Font Name from an Otf or Ttf File
Simple and Clean Way to Convert JSON String to Object in Swift
Programmatically Set Image to Uiimageview with Xcode 6.1/Swift
How to Stop Multiple Times Method Calling of Didupdatelocations() in iOS
Swift Countelements() Return Incorrect Value When Count Flag Emoji
Swift Function Returning a Value from Asynchronous Firebase Call
Why Xcode 7 Shows *.Tbd Instead of *.Dylib
Detecting iOS Uidevice Orientation
Swift - How to Remove a Decimal from a Float If the Decimal Is Equal to 0
Receiving Push Notifications While in Background
How to Keep Uitableview Contentoffset After Calling -Reloaddata
How to Change Wkwebview or Uiwebview Default Font
Making a Button Persistent Across All View Controllers
How to Fill a Uibezierpath with a Gradient
Storing Asynchronous Cloud Firestore Query Results in Swift
Unbalanced Calls to Begin/End Appearance Transitions for <Uitabbarcontroller: 0X197870>
Setting Selected Image in Tab Bar Controller with Storyboard