How to release IBOutlet defined as property? - iphone

sorry for this question, but I searched it and I didn't find an answer for that case.
I'm studying memory management for iOS and I understood, or I think so, the view lifecycle. But now I have a question on a IBOutlet (tat is linked to a UIImageView in my xib file).
I have a class like this:
#interface MyClass : UIViewController
#property (nonatomic, retain) IBOutlet UIImageView *myImage;
The question is: how can I release myImage? Is this ok?
- (void)dealloc {
self.myImage = nil;
[super dealloc];
}
- (void)viewDidUnload {
[super viewDidUnload];
self.myImage = nil;
}
Can someone explain why can't I call the release method on myView (if you had some lik it is good too!)?
Thanks in advance!

IBOutlet have nothing to deal with memory management.
But because it is retain property, so you need to release it in dealloc.
So your code is correct.

In general, you don't call release on a property, you would call it on the corresponding ivar. This is my standard way to handle IBOutlet properties:
#interface MyClass
#property (nonatomic, retain) IBOutlet UIImageView *myImageView;
#property (nonatomic, retain) IBOutlet UILabel *myLabel;
#end
#implementation MyClass
#synthesize myImageView = _myImageView;
#synthesize myLabel = _myLabel;
- (void)dealloc {
[_myImageView release];
[_myLabel release];
[super dealloc];
}
#end

What you are doing is correct, and you generally shoudnt call release on the properties, since setting to nil does that already, however if you have a backing ivar to your property you can call release on that...

There's a property and an instance variable behind the property. They both are called myImage, I presume (or you wouldn't be asking this question). You can free the instance in two ways - either release and nil the ivar, or just nil the property.
The compiler-generated setter for retained properties (like this one) works as following: release the currently held object reference (if any), assign the new value to the underlying ivar, retain it (if not nil). So when you assign nil to a property, it has the effect of releasing the current value and replacing it with nil.
To do that, use
self.myImage = nil; //invoke property setter behind the scenes
To free an ivar, use
[myImage release];
myImage = nil;
This is functionally equivalent to the code above. Marginally faster. The thing you should be clear about is the distinction between properties and backing ivars. For that very reason, some people make a point of assigning different names to them, and synthesizing like this:
#synthesize MyImage = _MyImage;

From Apple's documentation:
Legacy Patterns Prior to ARC, the rules for managing nib objects are
different from those described above. How you manage the objects
depends on the platform and on the memory model in use. Whichever
platform you develop for, you should define outlets using the
Objective-C declared properties feature.
The general form of the declaration should be:
#property (attributes) IBOutlet UserInterfaceElementClass *anOutlet;
Because the behavior of outlets depends on the platform, the actual declaration differs:
For iOS, you should use:
#property (nonatomic, retain) IBOutlet UserInterfaceElementClass *anOutlet;
For OS X, you should use:
#property (assign) IBOutlet UserInterfaceElementClass *anOutlet;
You should then either synthesize the corresponding accessor methods,
or implement them according to the declaration, and (in iOS) release
the corresponding variable in dealloc.
This pattern also works if you use the modern runtime and synthesize
the instance variables, so it remains consistent across all
situations.

First of all: consider switching to ARC if you aren't supporting iOS versions prior to 4.0.
Secondly, the best practice of writing dealloc methods says not to invoke setters. Instead, expressly release and nil your outlets:
[myImage release], myImage = nil;
Finally, when chaining together de-initialization methods like viewDidUnload, always call super's implementation after you do your own work.
The reason we nil out outlets in viewDidUnload is because sometimes views are unloaded when the system is under memory pressure. Since these outlets can be recreated easily, implementing viewDidUnload is a way to help performance, and in extreme situations, prevent your app from being forcefully terminated.
The reason we release properties in dealloc is to prevent memory leaks. So even though these two methods can look quite similar, they serve somewhat different purposes.

I don't really get what you mean by "why can't I call the release method on myView"
Your code seems correct to me but by convention I usually prefer to release the iVar directly for a retained property
I usually synthesize my property like this :
#synthesize myImage = _myImage;
And then you I release the iVar in the dealloc method
- (void)dealloc {
[_myImage release];
[super dealloc];
}
Anywhere else in the Controller I just go for the getter and setter (the dot convention)
Your viewDidUnload is correct.
By the way, if you're using ARC just declare your IBOutlet as a weak pointer. It will be automatically released in low memory situations and reloaded as soon as your view is loaded back again.
Hope this will help ;)

Related

Need to release IBOutlet object?

I have dilemma about Memory releasing IBOutlet object.Do anyone please suggest what to do when we create IBOutlet object without property, need to release it?? if need to release... why we are releasing it
The answer is YES.
The runtime connects the objects to IBOutlet using [setValue:ForKey:]. This function will find the private instance variables, retain the target and set it to the instance variable. Please visit here iOS Developer Library to know more.
I highly recommend you to read the article because many iOS framework accesses properties by Key-Value compliance ([setValue:ForKey:] or [valueForKey:]), instead of directly calling getters/setters/instance variables.
IBOutlet does not change the ownership semantics of properties. If you do not use ARC you have to release retained objects as with any other property.
Just Set it to default, which is "Weak". Then you are fine with ARC.
Why not just have a private IBOutlet property, to make things clearer and more explicit. I always do this personally:
MyClassName.m
#interface MyClassName ()
#property (nonatomic, weak) IBOutlet NSObject *myPropertyNameForAnOutlet;
#end
#implementation MyClassName
...
#end
You are not the owner of that object. so no need to release IBOutlet object.If you are using #property (nonatomic, retain) on IBoutlet object then you must release that object in dealloc.
Take a look at Advanced Memory Management Programming Guide
You must not relinquish ownership of an object you do not own
Answer is YES...
i was confused about that too, but try this:
open a xib file
onen assistant editor window and get the .h file code near your XIB IB file
chose an object in IB file (an object with no reference to any var)
ctrl click on it and chose: "new reference outlet" button
drag the line to your .h code file in the #interface{ } section
give a name to your new var ("aaa")
(note that no property "aaa" is created)
now Xcode has done all the magic for you, and...
in .m file you can find, in dealloc method:
- (void) dealloc {
[aaa release];
[super dealloc];
}
so... if apple release it, it seems that the default IBOutlet vars loaded via XIB file are retained...
EDIT:
here's the point in apple doc:
You are not the owner of the object, therefore you do not release it.
You become the owner by retaining, copying or creating (init/alloc) an object. Only then you are you (one of the) owner(s) of the object, and need to release it when you are done with the object. Fore more info check
Cocoa core competencies - Memory Management
I hope this explains why you do not have to release the object.
Even though you didn't set it as property, the property is refer to setter and getter methods. When you use an object you should always remember to release it. The property is unrelated with memory issue.

Objective-C property

I'm developing an Iphone app. I read from a book about declaring a property like below:
#property (nonatomic, retain) NSArray *listData;
Then in the implementation file, dealloc method, must put something like:
[listData release];
I wonder if I declare as
#property NSArray *listData;
do I have to release it? It'll save 1 line of code for me.
Yes, you have to release it. The retain qualifier means that when you set the property, your class will call retain on the NSArray. When your class is done, you need to release anything that you have retained, otherwise you have a memory leak.
#property NSArray *listData;
will just implicitly declare your accessor and mutator methods for listData,
but what about memory management(it's a serious stuff as far as iphone app development is concerned)?
If you going to use it in implementation then you should release it in dealloc method
also refer Official Apple docs for #property

release everything you have an #property retain #synthesize for?

I started banging away on my app and have gotten way deep and it is running great but I think I let some stuff run a little wild.
For every #property (nonatomic, retain) that then I create an #synthesize for I need to have [variable release] in the dealloc method - is this correct?
Even if it is an IBOutlet?
Yes. You declared ownership of the object by making it a retain property, which means you must relinquish ownership by releasing it.
In addition, if you have a retained IBOutlet, you should release it and set it to nil in -viewDidUnload. That lets the object release its outlets when the view is removed, particularly in response to a low memory warning. By setting the ivar to nil in that method, you avoid the risk of double-releasing the ivar if the object is subsequently deallocated.
Yes. If you retain the property you are responsible for releasing it.
Declared properties fundamentally take the place of accessor method declarations; when you synthesize a property, the compiler only creates any absent accessor methods. There is no direct interaction with the dealloc method—properties are not automatically released for you.
Declared Properties
Typically you will do this in your dealloc method.
- (void)dealloc {
[property release];
[super dealloc];
}

What happens if I don't retain IBOutlet?

If I do this:
#interface RegisterController : UIViewController <UITextFieldDelegate>
{
IBOutlet UITextField *usernameField;
}
instead of this:
#interface RegisterController : UIViewController <UITextFieldDelegate>
{
UITextField *usernameField;
}
#property (nonatomic, retain) IBOutlet UITextField *usernameField;
Will something bad happen? I know in the second case, the field is retained, but does this make a different since the nib owns the field? Will the field go away without the retain? and under what circumstances? The code in the first case works, was wondering whether this is an issue or not in terms of memory management.
It is recommended you declare properties for all of your IBOutlets for clarity and consistency.
The details are spelled out in the Memory Management Programming Guide. The basic gist is, when your NIB objects are unarchived, the nib loading code will go through and set all of the IBOutlets using setValue:forKey:. When you declare the memory management behavior on the property, there is no mystery as to what is going on. If the view gets unloaded, but you used a property that was declared as retain, you've still got a valid reference to your textfield.
Perhaps a more concrete example would be useful to indicate why you should use a retaining property:
I'm going to make some assumptions about the context in which you're working--I'll assume the UITextField above is a subview of another view that is controlled by a UIViewController. I will assume that at some point, the the view is off the screen (perhaps it is used in the context of a UINavigationController), and that at some point your application gets a memory warning.
So lets say your UIViewController subclass needs to access its view to display it on screen.
At this point, the nib file will be loaded and each IBOutlet properties will be set by the nib loading code using setValue:forKey:. The important ones to note here are the top level view that will be set to the UIViewController's view property, (which will retain this top level view) and your UITextField, which will also be retained. If it is simply set, it'll have a retain put on it by the nib loading code, otherwise the property will have retained it. The UITextField will also be a subview of the top level UIView, so it will have an additional retain on it, being in the subviews array of the top level view, so at this point the text field has been retained twice.
At this point if you wanted to switch out the text field programmatically, you could do so. Using the property makes memory management more clear here; you just set the property with a new autoreleased text field. If you had not used the property, you must remember to release it, and optionally retain the new one. At this point it is somewhat ambiguous as to whom owns this new text field, because the memory management semantics are not contained within the setter.
Now let's say a different view controller is pushed on the UINavigation Controller's stack, so that this view is no longer in the foreground. In the case of a memory warning, the view of this offscreen view controller will be unloaded. At this point, the view property of the top level UIView will be nulled out, it will be released and deallocated.
Because the UITextField was set as a property that was retained, the UITextField is not deallocated, as it would have been had its only retain been that of the subviews array of the top level view.
If instead the instance variable for the UITextField not been set via a property, it'd also be around, because the nib loading code had retained it when setting the instance variable.
One interesting point this highlights is that because the UITextField is additionally retained through the property, you'll likely not want to keep it around in case of a memory warning. For this reason you should nil-out the property in the -[UIViewController viewDidUnload] method. This will get rid of the final release on the UITextField and deallocate it as intended. If using the property, you must remember to release it explicitly. While these two actions are functionally equivalent, the intent is different.
If instead of swapping out the text field, you chose to remove it from the view, you might have already removed it from the view hierarchy and set the property to nil, or released the text field. While it is possible to write a correct program in this case, its easy to make the error of over-releasing the text field in the viewDidUnload method. Over-releasing an object is a crash-inducing error; setting a property that is already nil again to nil is not.
My description may have been overly verbose, but I didn't want to leave out any details in the scenario. Simply following the guidelines will help avoid problems as you encounter more complex situations.
It is additionally worth noting that the memory management behavior differs on Mac OS X on the desktop. On the desktop, setting an IBOutlet without a setter does not retain the instance variable; but again uses the setter if available.
Declaring something IBOutlet, from a memory management standpoint, does nothing (IBOutlet is literally #defined as nothing). The only reason to include IBOutlet in the declaration is if you intend to connect it in Interface Builder (that's what the IBOutlet declaration is for, a hint to IB).
Now, the only reason to make an #property for an instance variable is if you intend to assign them programatically. If you don't (that is, you're only setting up your UI in IB), it doesn't matter whether you make a property or not. No reason to, IMO.
Back to your question. If you're only setting this ivar (usernameField) up in IB, don't bother with the property, it won't affect anything. If you DO make a property for usernameField (because you're programatically creating it), definitely do make a property for it, and absolutely DO make the property retain if so.
In fact there are two models:
THE OLD MODEL
These model was the model before Objective-C 2.0 and inherited from Mac OS X. It still works, but you should not declare properties to modify the ivars. That is:
#interface StrokeWidthController : UIViewController {
IBOutlet UISlider* slider;
IBOutlet UILabel* label;
IBOutlet StrokeDemoView* strokeDemoView;
CGFloat strokeWidth;
}
#property (assign, nonatomic) CGFloat strokeWidth;
- (IBAction)takeIntValueFrom:(id)sender;
#end
In this model you do not retain IBOutlet ivars, but you have to release them. That is:
- (void)dealloc {
[slider release];
[label release];
[strokeDemoView release];
[super dealloc];
}
THE NEW MODEL
You have to declare properties for the IBOutlet variables:
#interface StrokeWidthController : UIViewController {
IBOutlet UISlider* slider;
IBOutlet UILabel* label;
IBOutlet StrokeDemoView* strokeDemoView;
CGFloat strokeWidth;
}
#property (retain, nonatomic) UISlider* slider;
#property (retain, nonatomic) UILabel* label;
#property (retain, nonatomic) StrokeDemoView* strokeDemoView;
#property (assign, nonatomic) CGFloat strokeWidth;
- (IBAction)takeIntValueFrom:(id)sender;
#end
In addition you have to release the variables in dealloc:
- (void)dealloc {
self.slider = nil;
self.label = nil;
self.strokeDemoView = nil;
[super dealloc];
}
Furthermode, in non-fragile platforms you can remove the ivars:
#interface StrokeWidthController : UIViewController {
CGFloat strokeWidth;
}
#property (retain, nonatomic) IBOutlet UISlider* slider;
#property (retain, nonatomic) IBOutlet UILabel* label;
#property (retain, nonatomic) IBOutlet StrokeDemoView* strokeDemoView;
#property (assign, nonatomic) CGFloat strokeWidth;
- (IBAction)takeIntValueFrom:(id)sender;
#end
THE WEIRD THING
In both cases, the outlets are setted by calling setValue:forKey:. The runtime internally (in particular _decodeObjectBinary) checks if the setter method exists. If it does not exist (only the ivar exists), it sends an extra retain to the ivar. For this reason, you should not retain the IBOutlet if there is no setter method.
There isn't any difference between the way those two interface definitions work until you start using the accessors provided by the property.
In both cases, you'll still need to release and set-to-nil the IBOutlet in your dealloc or viewDidUnload methods.
The IBOutlet points to an object instantiated within a XIB file. That object is owned by the File's Owner object of the XIB file (usually the view controller that the IBOutlet is declared in.
Because the object is created as a result of loading the XIB, it's retain count is 1 and is owned by your File's Owner, as mentioned above. This means that the File's Owner is responsible for releasing it when it's deallocated.
Adding the property declaration with the retain attribute simply specifies that the setter method should retain the object passed in to be set - which is the correct way to do it. If you did not specify retain in the property declaration, the IBOutlet could possibly point to an object that may not exist any more, due to it being released by its owner, or autoreleased at some point in the program's lifecycle. Retaining it prevents that object being deallocated until you're done with it.
Objects in the nib file are created with a retain count of 1 and then autoreleased. As it rebuilds the object
hierarchy, UIKit reestablishes connections between the objects using setValue:forKey:, which uses the
available setter method or retains the object by default if no setter method is available. This means that any object for which you have an outlet remains valid. If there are any top-level objects you do not store in outlets, however, you must retain either the array returned by the loadNibNamed:owner:options: method or the objects inside the array to prevent those objects from being released prematurely.
Well, in the second case you're adding a getter/setter method for that particular IBOutlet. Any time you add a getter/setter method you (almost always) want to have it set to retain for memory management issues. I think a better way to have posed you're question would have been this:
#interface RegisterController : UIViewController <UITextFieldDelegate>
{
IBOutlet UITextField *usernameField;
}
#property (nonatomic) IBOutlet UITextField *usernameField;
or
#interface RegisterController : UIViewController <UITextFieldDelegate>
{
IBOutlet UITextField *usernameField;
}
#property (nonatomic, retain) IBOutlet UITextField *usernameField;
In that case, then yes, you would need to add a retain since it will affect memory management. Even though it may not have any effects, if you're programatically adding and removing IBOutlet's, you could potentially run into issues.
As a general rule: always add an #property (with retain) whenever you have an IBOutlet.

Do I need to release xib resources?

If I have something like a UILabel linked to a xib file, do I need to release it on dealloc of my view? The reason I ask is because I don't alloc it, which makes me think I don't need to release it either?
eg (in the header):
IBOutlet UILabel *lblExample;
in the implementation:
....
[lblExample setText:#"whatever"];
....
-(void)dealloc{
[lblExample release];//?????????
}
If you follow what is now considered to be best practice, you should release outlet properties, because you should have retained them in the set accessor:
#interface MyController : MySuperclass {
Control *uiElement;
}
#property (nonatomic, retain) IBOutlet Control *uiElement;
#end
#implementation MyController
#synthesize uiElement;
- (void)dealloc {
[uiElement release];
[super dealloc];
}
#end
The advantage of this approach is that it makes the memory management semantics explicit and clear, and it works consistently across all platforms for all nib files.
Note: The following comments apply only to iOS prior to 3.0. With 3.0 and later, you should instead simply nil out property values in viewDidUnload.
One consideration here, though, is when your controller might dispose of its user interface and reload it dynamically on demand (for example, if you have a view controller that loads a view from a nib file, but on request -- say under memory pressure -- releases it, with the expectation that it can be reloaded if the view is needed again). In this situation, you want to make sure that when the main view is disposed of you also relinquish ownership of any other outlets so that they too can be deallocated. For UIViewController, you can deal with this issue by overriding setView: as follows:
- (void)setView:(UIView *)newView {
if (newView == nil) {
self.uiElement = nil;
}
[super setView:aView];
}
Unfortunately this gives rise to a further issue. Because UIViewController currently implements its dealloc method using the setView: accessor method (rather than simply releasing the variable directly), self.anOutlet = nil will be called in dealloc as well as in response to a memory warning... This will lead to a crash in dealloc.
The remedy is to ensure that outlet variables are also set to nil in dealloc:
- (void)dealloc {
// release outlets and set variables to nil
[anOutlet release], anOutlet = nil;
[super dealloc];
}
I found what I was looking for in the Apple docs. In short you can set up your objects as properties that you release and retain (or just #property, #synthesize), but you don't have to for things like UILabels:
http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/LoadingResources/CocoaNibs/chapter_3_section_4.html#//apple_ref/doc/uid/10000051i-CH4-SW18
The
[anOutlet release], anOutlet = nil;
Part is completely superfluous if you've written setView: correctly.
If you don’t release it on dealloc it will raise the memory footprint.
See more detail here with instrument ObjectAlloc graph
Related: Understanding reference counting with Cocoa / Objective C
You do alloc the label, in a sense, by creating it in IB.
What IB does, is look at your IBOutlets and how they are defined. If you have a class variable that IB is to assign a reference to some object, IB will send a retain message to that object for you.
If you are using properties, IB will make use of the property you have to set the value and not explicitly retain the value. Thus you would normally mark IBOutlet properties as retain:
#property (nonatomic, retain) UILabel *lblExample;
Thus in ether case (using properties or not) you should call release in your dealloc.
Any IBOutlet that is a subview of your Nib's main view does not need to be released, because they will be sent the autorelease message upon object creation. The only IBOutlet's you need to release in your dealloc are top level objects like controllers or other NSObject's. This is all mentioned in the Apple doc linked to above.
If you dont set the IBOutlet as a property but simply as a instance variable, you still must release it. This is because upon initWithNib, memory will be allocated for all IBOutlets. So this is one of the special cases you must release even though you haven't retained or alloc'd any memory in code.