Should IBOutlets be ivars or properties? - objective-c

Though I'm sure they exists, I'm having difficulties finding or pinning down an official best practice for declaring outlets in a ViewController.
There are 3 options so far as I can see:
ivar only
property only
property backed with an ivar
Xcode currently crashes when I try and auto-generate a property by dragging into my ViewController from IB, but from what I remember, doing so creates a property without an ivar. It is also possible to drag into the ivar section and this will create an ivar without a property. This suggests that property-only and ivar only outlets are both OK with apple.
So in viewDidUnload we need to assign nil to any of our outlets, but what about dealloc. If we have used a property without an ivar, how can we release our outlet give that we are not supposed to use any accessors in an init or dealloc?
It seems to me that the only pattern which would allow us to release our outlet without an accessor is using a property backed with an ivar, so we can manually release our ivar in dealloc without using its accessor, however this is the one option which Apple's code-generation doesn't support.

As a rule of thumb, I usually create accessors for IBOutlets.
In ARC or non-ARC projects I usually do the following:
//.h (ARC)
#property (nonatomic, weak) IBOutlet UILabel* myLabel;
//.h (non-ARC)
#property (nonatomic, retain) IBOutlet UILabel* myLabel;
//.m
#synthesize myLabel;
In this manner you can let the compiler to create an instance variable for you. But you can also declare your instance variable and tell the compiler to use that.
Then you can use that accessors/instance variable wherever you want.
The Apple Memory Management guide says that you have to avoid accessors methods in init or dealloc methods when you have non-ARC projects. So, for example:
// (non-ARC)
- (void)dealloc
{
[myLabel release]; myLabel = nil; // I'm using the instance variable here!
[super dealloc];
}
This is very important in non-ARC projects. The reason is that, if there is no accessor, KVC will assign the nib object to the instance variable and will put a retain on it. If you forget to release it, you could have a memory leak. Using an accessor force you to release that object at the end.
I strongly suggest to read friday-qa-2012-04-13-nib-memory-management by Mike Ash. It's a very cool article on nib and memory management.
Hope it helps.

Here's my understanding
Use properties for variables that will be accessed by other classes, either read from (getters) or written to (setters). Both setters and getters are synthesized for properties.
Use ivars for variables that will be used internally by the owning class only, that is, other classes will not set or get their values.
Sure you can use properties in lieu of ivars, but they incur the function-call overhead whenever they're accessed. So if you have an internal variable that is accessed by your class a LOT, the function calls will affect the real-time performance, and this can be avoided by declaring them as ivars.

Related

Why doesn't the managedObjectContext property synthesize its own instance variables ?

appDelegate.h
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
I had to do this in appDelegate.m
#synthesize managedObjectContext = _managedObjectContext;
I'm confused because according to apple
Note: The compiler will automatically synthesize an instance variable
in all situations where it’s also synthesizing at least one accessor
method. If you implement both a getter and a setter for a readwrite
property, or a getter for a readonly property, the compiler will
assume that you are taking control over the property implementation
and won’t synthesize an instance variable automatically. If you still
need an instance variable, you’ll need to request that one be
synthesized: #synthesize property = _property;
According to this it should create an instance variable as long as it created at least one accessor method. So does this mean that no accessors methods where created when I declared the property? What is the reason. Please explain.
I'm assuming somehow the compiler knows that NSManagedObjectContext has accessor methods. So it didn't create any and therefor it didn't create instance variables.
You haven't shown the code for the corresponding .m file, but I'm assuming you implemented the managedObjectContext property getter method programmatically. As the documentation says, "The compiler will automatically synthesize an instance variable in all situations where it’s also synthesizing at least one accessor method." But if you provide an implementation of the getter method for a readonly property, the compiler isn't synthesizing any accessor methods.
As the documentation says...If you provide atleast one accessor method for either setter or getter, its like telling the compiler...dont bother synthesizing this variable as I have some custom work to do with the setter/getter. Hence the compiler does not auto generate the _ivar. If you need the _ivar, you have to explicitly specify it and then proceed with your customer getter and setter. Its all about Objective C compiler doing things for you unless you say Don't bother...I know what I am doing.

Want to perform action when __weak ivar is niled

I have a #class Foo which contains a __weak id bar ivar. Several actions from methods in different classes can cause the object to disappear and thus get bar niled.
I want to perform an action when the ivar is automatically niled by ARC.
If possible, I would want to avoid turning bar into a property or using Key-Value Observing.
Is this even possible? If not, can KVO be used against non-property ivars?
I was led here by a duplicate question, here is what I answered:
You can't do that with KVO, but you can still get a notification and emulate this by associating an object with your iVar using objc_setAssociatedObject(), it will be deallocated when the weak variable dies.
#interface WeakObjectDeathNotifier : NSObject
#end
#implementation WeakObjectDeathNotifier
- (void)dealloc
{
// the code that shall fire when the property will be set to nil
}
#end
You can build on top of that very elaborate notifiers, using NSNotificationCenter or just custom blocks, depending on how heavily you rely on that for a specific ivar case or for lots of them.
The good thing about this solution is that it works with any __weak ivar, even if you don't control the type the __weak ivar has.
KVO cannot be successfully used on non-property IVARs.
You cannot detect from the runtime when Objective-C's ARC nils an IVAR.
I suggest to override dealloc. If you know the type of the object that will be allocated, and it's a custom class (otherwise subclass it), you can perform the action when the object is deallocated, which is exactly what happens when ARC sets the retain count to zero and sets the weak variable to nil.

Difference between declaring an attribute and a #property in objective-c

I know that the #property generates the getters and setters in Objective-c. But I've seen some classes where they declare attributes with their respective #property and some times just the #property with no attributes and seams to work the same way. Whats the difference?
I know that the #property generates the getters and setters in Objective-c.
No you don't. #property declares a property which is a getter and optionally a setter (for read/write properties). The generation of the getter and setter is done by the #synthesize in the implementation (or by you writing the getter and setter).
But I've seen some classes where they declare attributes with their respective #property
Do you mean like this?
#interface Foo : NSObject
{
Bar* anAttribute; // <<=== this is an instance variable
}
#property (retain) Bar* anAttribute;
#end
In the modern Objective-C run time, if you #synthesize the property, you can leave out the instance variable declaration and the compiler will put it in for you. Whether you explicitly declare the instance variable or not is a matter of personal preference.
Just to confuse you a bit, in the very latest compiler, you can omit the #synthesize and the compiler will put it in for you as long as you haven't explicitly created a getter or setter.
Under ios 5.0, there are ten different attributes you can attach to a property declaration: nonatomic, readwrite, readonly, getter=name, setter=name, strong, retain, copy, weak, assign. (strong, weak are new under ios 5.0 and are only meaningful if you use ARC).
nonatomic declares that variable access should not be protected against multithreaded concurrent access. This isn't the default, although 99% of the time it's what you want (since this protection makes your code run slower with no benefit if you're not doing multithreading).
readwrite/readonly should be fairly obvious - readwrite is the default, and if you declare a property readonly, it has no setter.
getter=, setter= control what the getter & setter methods should be called. If you omit them, they'll be called property name and set*property name*, respectively.
The remaining attributes (strong, weak, retain, copy, assign) are hints to the memory manager, and their behavior varies depending on whether you're using ARC or not. If you're not, then the "retain" property tells the setter method to automatically call retain on any object that it gets a reference to. This means that you must also call release in the deallocator.
The "assign" property tells the setter not to call retain - so if the object is released by another object, this pointer could be left dangling.
The "copy" property tells the setter to call retain and also to make a copy of the property - this is useful when you get, say, an NSDictionary and you don't want the caller to pass an instance of NSMutableDictionary and change the contents out from underneath you.
If you're using ARC, you'll normally only set "strong" or "weak". (strong is a synonym for retain, so they can be used interchangeably). "strong" tells ARC to retain the variable for you - "weak" tells it not to. "weak" is useful when you have a potential "retain cycle" where object A refers to object B and object A - if they both retain each other, you have a memory leak, so you'll want to make one of them a weak reference.

Do I need to release objects that I don't retain?

I am keeping a reference to the example object but I never use retain, new, or copy.
#interface ExampleViewController : UIViewController
{
IBOutlet UILabel *example;
}
#end
If I connect a UILabel object in Interface Builder to example, the retain count is two. But when I don't connect it, the retain count is zero. I would think that I am keeping one reference and the view is keeping another, therefore I would need to release it. What do you think?
IBOutlet instance variables are a special case. In iOS, each IBOutlet instance variable is retained when the NIB is loaded, so you do need to release them yourself.
In fact, you should take special care to release and nil these IBOutlets in -viewDidUnload:, otherwise they'll leak when the NIB is reloaded.
Note that this is actually different from Mac OS X development, where IBOutlets are not retained unless it's a top-level NIB object without a parent view or window.
For this reason, Apple now recommends exposing IBOutlets via properties rather than instance variables. That way, the ownership of the outlet is clearly defined.
#property (nonatomic, assign) IBOutlet UIButton* myButton;
#property (nonatomic, retain) IBOutlet NSObject* someObject;
myButton would not have to be released; someObject would have to be released. And in both cases, you're responsible for cleaning up these variables in -viewDidUnload:.
If you’re using ARC, then you don’t need to release an instance variable, as it’ll be released when your instance is deallocated. If you aren’t using ARC, you should write your -dealloc method in ExampleViewController as such:
- (void)dealloc
{
[example release];
[super dealloc];
}
Note that if you set example manually without using ARC, it is not automatically retained. Since you’re using a nib, however, it will be retained when it’s set up.
You need to release them in - (void) dealloc if you're not using ARC and there is a property for your IBOutlet, and you need to release and nil them in viewDidUnload:.
Consider using ARC (Automatic Retain Counting) for you project. With ARC the compiler takes care of retain counts so you don't have to, in fact aren't allowed to. There is a refactoring that will convert a current project.

Why Objective-C properties are sort of inconvenient?

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.