How to release the objects which are in Xib in iphone - iphone

In my .h file create 3 objects like below
IBOutlet UIScrollView *scrollView;
IBOutlet UITextView *txtMessage;
IBOutlet UIWebView *webView;
In xib make Connection for all 3 objects
hierarchy in xib like
**View
---UIScrollView
---UITextView
---UIWebView**
then I am printing retainCount in dealloc method
NSLog(#"scrollView retainCount:%d",[scrollView retainCount]);
[scrollView release];scrollView=nil;
NSLog(#"txtMessage retainCount:%d",[txtMessage retainCount]);
[txtMessage release];txtMessage=nil;
NSLog(#"webView retainCount:%d",[webView retainCount]);
[webView release];webView=nil;
on console i am getting like below
scrollView retainCount:3
txtMessage retainCount:2
webView retainCount:2
I want to know why its happens like this ,and one more thing how can release this objects in dealloc method...

The answer is: you don't release them. You didn't alloc] init] then, they're not your responsibility memory-wise.
The only case where they're somehow your responsibility, is when you retain them using a #property (retain) for the IBOutlets. In that case, you'll release them in [dealloc]
Answering to your comment in another answer about instruments and releasing the outlets that the xib creates: if you release them, then the view will be unload sometime and the responsible for releasing the elements in the .xib (which it wasn't you) will release them again, and it will crash ;) The reason why you go back to another view and the memory doesn't decrease is because when a view disappears, it's not unloaded, that only happens when either the view controller is deallocated, or when the application gets a memory warning.

I don't think you need to do anything in dealloc. In Objective-C, if you haven't alloc/retain anything, you don't need to worry.

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.

Retain vs Assign for controls inside NIB/XIB using the iPhone SDK

I'm using Interface Builder to build my rootViewController, which is retained by my application delegate. I have a few controls in this XIB such as a couple UIButtons, a UISlider, etc. as IBOutlets, hooked up properly in Interface Builder.
On the code implementation side of the XIB, I've seen some people use:
#interface RootViewController : UIViewController {
IBOutlet UIButton *button1;
IBOutlet UIButton *button2;
...
}
#property(nonatomic, assign) UIButton *button1;
#property(nonatomic, assign) UIButton *button2;
#end
Why do they use assign instead of retain? I've seen some people not even use an assign property.
Is it pointless to use retain since the rootViewController's XIB will always contain a reference to them as long as it is loaded? Or are they just being lazy and not going through the steps to retain, synthesize & dealloc? Seems to me like it can't hurt to keep a reference around as long as the control is needed and the viewController hasn't been dealloc'ed, but just wondering if XIB's do something differently where this wouldn't be necessary.
I've read the memory management guide, btw.
Thanks!
It cant hurt to keep all subviews as assigned instead of retained as long as they stay a child from there superview.
When you remove it from its superview and want to add it as a subview later on in your code. Thats not possible. When you remove it from its super its retain count will probably turn to zero. Thats one of the reasons why you use retain. Your controller object will then always be a owner of the view object.
I cant think of other reasons you must use retain instead of assign.
I always use retain, i think its a best practice for outlets and it seems to be a convention.

addSubview of UIViewController, view gets over released

EDIT:
Solved the problem myself. Turned out it was a leftover in the dealloc method that caused a UIButton to be released twice...
I'm trying to display a UIViewController on top of another UIViewController like a popup. Problem is that the view seems to be getting overreleased. With NSZombieEnabled, I get the following error:
[CALayer release]: message sent to deallocated instance 0x784bf40
I use this code to add the view:
//self.someViewController is declared as (nonatomic, retain)
self.someViewController = [[[SomeViewController alloc] initWithDelegate:self] autorelease];
[self.view addSubview:self.someViewController.view];
Then later on, I remove the view like this:
[self.someViewController.view removeFromSuperview];
self.someViewController = nil;
Should earlier comments not solve this perhaps this may help. I'm assumning you've created your someViewController property like this
#property (nonatomic, retain) NSViewController* someViewController;
in which case I believe your code is correct (at least I can see how it should work) and you might be seeing a secondary crash here.
I.e. when you're calling
self.someViewController = nil;
this should be freeing the memory up immediately (assuming a frame has gone by where the VC exists so the autoreleased count has already been decreased). Therefore if you have ANOTHER object being used in that someViewController VC who still exists and has a delegate set to your someViewController object and is doing a background task it will cause a crash when it trys to call back to your now deallocated object. (If you don't free your VC you wouldn't see this crash)
For example if you have a MKMapKit being displayed in someViewController and the delegate is set to someViewController... if you have implemented the method in someViewController
mapViewDidFinishLoadingMap:(MKMapView*)mapView
the MKMapKit may still be calling this from another thread if you haven't destroyed MKMapView object before yours.
I would always set other object delegates pointing to your VC (like MKMapView) to nil before destroying the said VC it uses to avoid this risk. For PDF rendering (CALayer?) you may find you need to explicitly release the object too given this uses a different memory alloc/free paradigm.
Solved the problem myself. Turned out it was a leftover in the dealloc method that caused a UIButton to be released twice...

Properly releasing UITableViewController and UITableView directly added to a UIViewController

I have a UIViewController (parentVC) to which I add a UITableViewController as follows (it is not pushed since the tableview only occupies about half the screen):
tableVC = [[SmallTableVC alloc] initWithStyle:UITableViewStylePlain];
[self.view addSubview:tableVC.tableView];
In dealloc, I add [tableVC release];
Using instruments, I can see that the tableVC is indeed fully released when parentVC released, which is good, but I am not sure why as I thought that the UITableView of tableVC would have a retain count of 2 (1 for retention by tableVC and 1 for retention by parentVC). My intuition was that an additional [tableVC.tableView release] would be required, but adding it crashes the app. Why is tableVC released properly by the current code (if indeed it actually is)? Does a UITableViewController not retain its tableView? Thanks.
You are allocating tableVC, so retain count is 1. You do not pass tableVC to anything else, so there is no reason anything else would retain it. If something else did retain tableVC, it would be responsible for releasing it when it no longer needed it.
If you were to look at the retain count of the UITableView owned by tableVC it might be higher than one, as it is retained by both tableVC and, after you call addSubview, the view owned by parentVC.
Edit:
If you want to forcibly clean up tableVC.tableView then call removeFromSuperview before releasing tableVC. I believe that view controllers implicitly do this when released, but it does not hurt to do it manually as well.
After you call [self.view addSubview:tableVC.tableView] tableVC.tableView will have a retain count of at least two. One for the view hierarchy and one for tableVC. When you release tableVC it is removing the tableView from the view hierarchy which releases tableView, then it is releasing tableView itself. Even if it was not removing tableView from the view hierarchy, parentVC.view is about to be torn down and release the view hierarchy that included tableVC.tableView.
Only release what you have explicitly retained. The naming conventions make this pretty clear. If the name includes retain, new, alloc or copy then you should release the result.
Be careful trusting retain counts on iPhone. iPhone does not do real garbage collection and therefore these values should be ignored. Follow the memory management rules and you will be fine.
In this case, the tableVC will be released in "dealloc" and the view it controlled will be released in [super dealloc].
Do not trust retain counts!

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.