Do I need to release xib resources? - iphone

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.

Related

Does a subview viewcontroller added via addSubiew need a dealloc?

normally when I'm using a viewcontroller that will push the current viewcontroller out of the way, I use a UINavigationController and push/pop the new viewcontrollers and let them handle all the dealloc themselves.
However, for example, in this case, I have a MainViewController, which is the default view when the app starts up. I have a second view, called SecondaryViewController, that is a popup on the main screen (sort of like a lightbox).
Here is the code to illustrate:
//From within mainViewController:
secondaryViewController = [SecondaryViewController alloc] initWithNibName:#"SecondaryViewController" bundle:nil];
[self.view addSubview:secondaryViewController.view];
The secondaryViewController interface looks like this:
//interface
#interface SecondaryViewController : UIViewController
{
IBOutlet UILabel *httpLabel;
IBOutlet UIScrollView *scrollView;
}
#property(retain, nonatomic) IBOutlet UILabel *httpLabel;
#property(retain, nonatomic) IBOutlet UIScrollView *scrollView;
As for the implementation, I have the #synthesize for the #property ivars, but I'm not doing any manual allocs. However, I did put a dealloc method:
- (void)dealloc
{
[httpLabel release];
[scrollView release];
[super dealloc];
}
But I'm not sure I need the above.
So my questions would be the following:
1) Do I need the above dealloc method in this case? Or more generally, when would a subview need a dealloc method?
2) If I do or dont need it, does it depend on whether I'm adding the secondaryViewController via addSubview or pushViewController? For instance, if I wanted to replace the entire mainViewController, with this:
[self.navigationController pushViewController:secondaryViewController animated:NO]
Would the secondaryViewController need a dealloc method?
Thank you!
Yes, you do need the dealloc method exactly as you have it, in this case. You are on the right track because you're assuming that since you are not doing any manual allocating, you don't need to do any dealloc/releasing... however, by specifying the property as (retain, nonatomic), you are doing implicit retaining.
This means that if you ever set those properties, what's actually occurring under the covers is something like this:
-(void)setHttpLabel:(UILabel *)newlabel
{
if (newLabel != httpLabel)
{
[httpLabel release];
httpLabel = [newLabel retain];
}
}
As you can see, your synthesize is causing a retain to occur on an object. If you never balance that retain out with a release, it will leak. So the only logical place to put it, is in your dealloc method. This creates the circle of life.
If you never set these properties and don't have release in dealloc, then it won't leak anything, but you obviously wouldn't want to make those assumptions.
If you didn't have any retain properties or any manual allocing of ivars, then and only then, can you nuke the dealloc method.
Hope that helps.
I think this is allowed in the latest iOS 5+ but previously you were not supposed to add another viewcontrollers view to your main viewcontroller. This is clear misuse and can lead to issues.
The concept of viewcontroller is one who controls all the views. A view controller should not control another viewcontroller unless it is a container viewcontroller such as UINavigationController/UITabBarController.
So please rethink the design. why do you need the SecondaryViewController. Why cannot the mainviewcontroller manage the secondary view as well?
Lastly, every viewcontroller should have the dealloc in it.
If you need to access secondaryViewController from your main view controller after you've added its view to the hierarchy, you should not deallocate it at that point. If you don't need to access the secondary controller after you've displayed it, you can dealloc it at that point.
In practical terms, if secondaryViewController is an ivar, it probably makes sense to keep a retained reference to it. If it's a local variable and you're not accessing it later, you should dealloc it.

How to release IBOutlet defined as property?

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 ;)

Do IBOutlet member vars retain automatically?

Weird discovery, when I used a drag and drop to make a new IBOutlet, as shown below, not with a #property at all:
#interface SkinChoosingView : UIViewController {
IBOutlet UIActivityIndicatorView * activityIndicator;
}
Xcode inserted a -release and set the outlet to nil in viewDidUnload. I looked in viewDidLoad though, and no -retain was there! This went against everything I know about memory management.
I figure apple must know a thing or two about this stuff though, so is there something behind the scenes happening here? I have never had leaks from these types of IBOutlets, and I've never released them.
Yes, it automatically retains the outlet for you when loading the NIB file unless you explicitly declare the property associated with the outlet as an assigned property.
And since it retains the outlet for you, you must release in viewDidUnload as the outlets will be reloaded by the time next viewDidLoad is called.
The answer is that it uses "Key-Value Coading", which means it calls -setValue:forKey:, which has a "Default Search Pattern". For ivars, it does something like [ivar autorelease]; ivar = [newvalue retain];.
The "current best practice" is to stick IBOutlet on properties instead of ivars (see here). This makes it obvious what memory management pattern is being used and is more resilient to typos (e.g. if you misspell the ivar).

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];
}

Iphone: Where to release objects?

where i should release objects: in method dealloc or viewDidUnload?
Thanks
The correct way is to release them and set them to nil in both of those methods.
You need to release your objects in viewDidUnload since memory warnings can happen, and if your view doesn't have a superview then you should release your outlets to save memory. The framework will issue a viewDidLoad again if the view was unloaded.
You need to release your objects in dealloc, since viewDidLoad + viewDidUnload is not necessarily called.
Finally you need to set your variables to nil in both of the methods, to not be able to call release on them the second time.
A short answer for you question: dealloc()
A long and more complicated answer for your question: both
release any unused IBOutlets in viewDidUnload(). This method will be called when your device is running out of memory.
release any objects that the current view controller is responsible for memory management, and release them in dealloc(). (An autoreleased object doesn't belong to this category)
Any objects allocated and/or retained as part of loadView and/or viewDidLoad should be released in viewDidUnload. Releasing anything you alloc in viewDidLoad is easy to grasp, loadView is a bit harder if you are using a NIB. Any IBOutlet that is a property defined as retain will be implicitly retained as part of loadView.
If the view have for example a subview that is a UITextField and you connect this view to a property defined as:
#property(nonatomic, retain) IBOutlet UITextField* nameField;
Then the actual text field when loaded from the NIB will have a retain count of +2. +1 because of it's parent view, and +1 because of the property you connected it too. Thus it's memory is not freed until the view controller is released, or the NIB is loaded again.
Unfortunately viewDidUnload is not called when a view controller is deallocated. So you must explicitly release all your `IBOutlets here as well. I use this patter in order to not forget to release anything:
-(void)releaseOutlets {
// Set all outlets to nil
}
-(void)viewDidUnload {
[self releaseOutlets];
[super viewDidUnload];
}
-(void)dealloc {
[self releaseOutlets];
// Release anything else.
[super dealloc];
}
dealloc this way if the parent object is released the child objects will be released as well.