Should I Declare Variables in Interface or Using Property in Objective-C Arc

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:

  1. You synthesize properties, not instance variables, and in your example, you showed us an example of an instance variable, not a property.

  2. 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 do retain and release is a function of whether you are using ARC or not. It has nothing to do with synthesizing properties.

  3. As others have observed, explicitly declared instance variables, such as your example, are strong references, by default. So, in your example, _pieces is a strong reference.

  4. Yes, when your SomeClass object is deallocated, it will remove its strong 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 other weak references you have to it elsewhere will be set to nil. For a more complete discussion on the memory management, see Apple's Advanced Memory Management Programming Guide and Transitioning to ARC.

  5. You asked "If all other objects that have retained _pieces release it, will it be nil when I attempt to access it?" Obviously that would be true if _pieces was a weak reference, but given that it's implicitly a strong reference in SomeClass, no, that is not the case.

  6. If you wanted to make pieces a declared property, the syntax would be

    @property (nonatomic, strong) NSMutableArray* pieces;

    The designation of strong vs. weak (or whatever) dictates the memory management of the property.

  7. 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.

  8. 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 your pieces property of the form:

    @synthesize pieces;

    then the instance variable will be called pieces. 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



Leave a reply



Submit