UIViewController pushViewController high retain count of View controller - objective-c

I wrote the following piece of code:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
GameViewController *gameViewController = [[GameViewController alloc]initWithLevelNumber:([levelGroup intValue]*100+indexPath.row) Bonus:NO];
NSLog(#"Retain Counter =%d",gameViewController.retainCount);
[navController pushViewController:gameViewController animated:YES];
[gameViewController release];
NSLog(#"Retain Counter=%d",gameViewController.retainCount);
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
The results of the two logs are, in sequence 1 and 6!
How this is possible? I only call the alloc method one time and release after push the controller on the stack.. alloc-> +1, push-> +1, release-> -1 = 1 or not?
I'd like the view controller is dealloc'd when i pop it off the stack..

Please read this note to be clear in this question. It is part of NSObject Protocol Reference:
Important: This method is typically of no value in debugging memory management issues. Because any number of framework objects may have retained an object in order to hold references to it, while at the same time autorelease pools may be holding any number of deferred releases on an object, it is very unlikely that you can get useful information from this method.
NSObject Protocol Reference. RetainCount discussion

Autorelease your GameController creation, like this:
GameViewController *gameViewController = [[[GameViewController alloc]initWithLevelNumber:([levelGroup intValue]*100+indexPath.row) Bonus:NO] autorelease];
Then delete [gameViewController release]; Then your code looks kosher, and gameViewController will be autoreleased after being popped from the nav stack. Don't worry about retainCount - when you push a view controller, UIKit takes over and will retain/release the thing as needed. You just have to worry about your code. Actually, the way you have it written should be fine, I just think my suggestions here make the code cleaner.
Unless you see in Instruments that you have a memory leak of your gameViewController object, I think you needn't worry.

It's because there is some retain internally (by pushViewController: method), you should not check the retain count, only check that you release the object you own, especially when you check retain count between sdk call methods.

Do you use NSNotificationCenter in your GameViewController?
May be you add your view controller as observer to NotificationCenter and it increase retainCount.

Related

How to release Instance variables?

I have a doubt that how we will release the instance variables properly.I know we can do the release in the dealloc method. If we are given as self.instancevariouble=nil in the viewdidunload also will release the object. My question is If there is any problem if we are given the object as nil in the unload method and then also release it in the dealloc method. Also how do I need to release a tableview which is added as IBoutlet in the xib.Can anybody point me in the right direction?
There is no problem with calling release on a nil object but, as a better strategy, move to ARC and most of these concerns will just go away. (Also note that iOS 6 does not unload views.)
If you try to release a nil object it will "work". You can send a message to a nil object without the app crash ;) so you can do this :
UILabel *lbl = nil;
[lbl release];
It won't do anything.
And about "How i need to release a tableview which is added as IBoutlet in the xib.Can anybody point me in the right direction?" You have to "connect" your UITableView in the xib file with your code and do a :
[myTableView release];
If you use self.instanceVariable = nil in the viewDidUnload method (which by the way does no longer get called in iOS 6) the value is of course nil. So if you then release that in the dealloc method you basically call [nil release]; and that does nothing.

autorelease vs. release in dealloc

I know memory management in iOS is tricky subject to newbies like me, but I was hoping for a clear explanation here on stackoverflow which I could not find anywhere else.
So, pretend I have a property / ivar
#property(nonatomic, retain) UIPopoverController *popOver;
which I'm allocating like this:
self.popOver = [[[UIPopoverController alloc] initWithContentViewController:popOverContent] autorelease];
Now, in my dealloc and viewDidUnload methods, I do both
// in viewDidUnload:
self.popOver = nil;
// in dealloc:
[popOver release];
Question:
If I do nil / release in viewDidUnload / dealloc, do I really need to autorelease at allocation?
Vice versa, if I do autorelease at allocation, do I need to nil / release later?
What's the difference, if any?
Thanks in advance for your time - I'll continue reading, seriously memory management can't be that hard to wrap your head around...
Don't be confused by the autorelease in this line:
self.popOver = [[[UIPopoverController alloc] initWithContentViewController:popOverContent] autorelease];
After this statement you effectively own the object because the property setter claimed ownership of it. The autorelease balances the alloc-init.
So... yes, you need to autorelease at allocation. If you did this (no autorelease), you would leak:
self.popOver = [[UIPopoverController alloc] initWithContentViewController:popOverContent];
Another option is to use a temporary variable instead of autorelease:
UIPopoverController *temp = [[UIPopoverController alloc] initWithContentViewController:popOverContent];
self.popOver = temp;
[temp release];
Either way you need to release the object in dealloc.
1 If I do nil / release in viewDidUnload / dealloc, do I really need to autorelease at allocation?
Yes.
2 Vice versa, if I do autorelease at allocation, do I need to nil / release later?
Yes.
In the first case, the auto-releasing is done on behalf of that method. That method doesn't need the popover anymore, so it needs to (auto)release it.
At dealloc, your object doesn't need the popover anymore. Therefore, you need to release it.
It's very simple. You don't have to consider long-term object ownership; you just need to think very locally, at the level of every method. The decision of releasing it or not doesn't at all depend on whether that object is kept by some other parts of the program. In a method, if you alloc an object and you no longer need it in that method, you (auto)release it.
The dealloc is a slight exception to the rule. There, you need to release the ownership of all the instance variables.
That's it!
Yes. But maybe not in this case.
Yes. But maybe not in this case.
viewDidUnload is called when the the view is unloaded, dealloc is called when the view Controller is being destroyed.
In viewDidUnload you release objects that are used by the view that are not needed anymore and can be recreated in viewDidLoad. Obvious, since the view is not being displayed it doesn't need to hold on to the objects that are set up by the view controller for it.
In dealloc you are cleaning up the viewController and here you clear up all it's resources, including those that it has assigned to the view.
In this case, the view does not own the popover controller - it should be owned by the view controller, so there is no need to release it in viewDidUnload but you do need to release it in the dealloc.

Object release in Objective-C: Why release an object twice in viewDidUnload and dealloc method?

I have a question about object release in objective-c. I saw some sample codes in Chapter 9 of "Beginning iphone 4 Development"(Page 287). The sample code release an object twice: both in viewDidUnload and dealloc method. Here are the sample codes:
- (void)viewDidUnload {
self.list = nil;
[childController release], childController = nil;}
- (void)dealloc {
[list release];
[childController release];
[super dealloc];}
childController is declared as an instance of UIViewController subclass. Why is it released in both viewDidUnload and dealloc method? Since childController is already released in viewDidUnload, is it necessary to release it again in dealloc method? Based my understanding I will write the code like:
- (void)viewDidUnload {
self.list = nil;
childController = nil;}
- (void)dealloc {
[list release];
[childController release];
[super dealloc];}
Thanks,
Sam
The problem is viewDidUnload is not guaranteed to be called every time like dealloc method. (check this question).
The reason to release objects in viewDidUnload is to avoid memory leaks. Since viewDidUnload is called when there's a low memory warning, you do want to clean up to avoid troubles in that case.
And also calling release on nil will not cause any problem, so it is safe to call release on retained objects in your dealloc method assuming the pointers are set to nil after been released elsewhere (like in viewDidUnload in your example).
In order to optimize available memory, is a good practice to implement lazy getters (actually lazy initializers) in UIViewControllers and release easily reallocable objects in viewDidUnload.
A (simplified) lazy getter is something like:
- (UIView *)footerView {
if (_footerView) {
return _footerView;
}
UIView *view = [[UIView alloc] initWithFrame:A_FRAME];
return (_footerView = view);
}
so, in the viewDidUnload I will release _footerView, because I can retrieve it later without effort. The release of _footerView in dealloc method, is not an error, because:
1) in objective c is ok to send messages to nil objects, 2) dealloc won't be executed at the same time as viewDidUnload but later
I've investigated a little bit because I was not sure. And all you need to know is here: When should I release objects in -(void)viewDidUnload rather than in -dealloc?
Basically, in viewDidUnload you release objects that you've created in the beginning of view's life cycle (loadView, viewDid load and so on). So if your viewController receives memory warning it will unload a view and reload it again and then your objects will be released in viewDidUnload and initialized again in loadView/viewDidLoad/ect

NSTableViewDataSource dealloc in objective-c

I'm currently learning objective-c and I'm currently training with NSTableView.
Here is my problem :
I have linked my tableview to my controller through Interface Builder so that it has a datasource, I have implemented NSTableViewDataSource protocol in my controller and I have implemented both -(NSInteger) numberOfRowsInTableView: and -(id) tableView:objectValueForTableColumn:row: methods.
I have created a raw business class ("person") and I succeeded to display its content into my NSTableView.
But then, I put some NSLog in my dealloc methods to see whether the memory was freed or not and it seems that my array as well as my "person" instances are never released.
here is my dealloc code in the controller:
-(void)dealloc
{
NSLog(#"the array is about to be deleted. current retain : %d",[personnes retainCount]);
[personnes release];
[super dealloc];
}
and in my "person" class
-(void) dealloc
{
NSLog(#"%# is about to be deleted. current retain : %d",[self prenom],[self retainCount]);
[self->nom release];
[self->prenom release];
[super dealloc];
}
When these deallocs are supposed to be called in the application lifecycle? Because I expected them to be called at the window closure, but it didn't.
In the hope of beeing clear enough,
Thanks :)
KiTe.
I’m assuming you’re never releasing the window controller object that owns the (only) window. As such, the window controller and every top level object in the nib file are retained throughout the application lifecycle, including the window (and its views).
Since the window controller exists throughout the application lifecycle, it isn’t released, hence its -dealloc method is never called. And, since the controller -dealloc method is never called, its personnes array isn’t released.
The personnes array owns its elements. Since the array isn’t released, neither are its elements, hence the -dealloc method of the corresponding class/instances is never called.
Don't ever use retainCount. The results are misleading at best. If you practice proper memory management practices, you'll be fine. Have you had any memory issues/crashes?

Few questions: Lifecycle of UIViewController; release vs setting to nil

I have a couple of questions relating to UIViewController:
1) When are each of the methods called for UIViewController? Specifically, the difference between viewDidLoad, viewDidUnload, and dealloc.
2) What's the difference, in general, when setting a pointer equal to nil and releasing the pointer? I know that in viewDidUnload you're supposed to set it equal to nil but in dealloc call release.
UPDATE: Sorry, just realized the question is misleading. Instead of dealloc, I meant -- when is initWithNibName:bundle: and release called? Just once by IB, right?
Setting a pointer to nil doesn't release the memory that it points to.
When you do something like
self.pointer = nil;
it's usually a case that the property has a retain attribute. When this is the case, setting the property to nil will indirectly cause a
[pointer release];
pointer = nil;
In the case of the view controller methods, viewDidLoad is called when your view is loaded, either from a nib, or programatically. More specifically, it's called just after -loadView is called. You shouldn't need to call loadView manually, the system will do it. The viewDidUnload method is called in the event of a memory warning and your view controller's view is not onscreen. Subsequently, loadView and viewDidLoad will get called again on demand.
The dealloc method, as normal, is called when your object's retain count reaches 0.
pointer = nil; // just clears the variable in which you store the pointer, but does not free memory.
[pointer release]; // just frees the object (memory), but does not clear the variable used to point to it.
self.pointer = nil; // sets the variable to nil. Also releases the object ONLY if pointer is a #property(retain) ivar.
One easy way to see when various methods are called is to do this in your UIViewController:
- (void)viewDidLoad
{
NSLog(#"MyViewController::viewDidLoad");
[super viewDidLoad];
// the rest of your viewDidLoad code, here.
}
// Etc., for the other methods of interest.
NOTE: much can be gleaned from overriding retain & release to log and then following along in the debugger.