Iphone - is controller freed after push? - iphone

is my UIViewController freed when i call another controller ?
How to release memory of controller when i push to another controller ? i take more than 40Mo and application leave because of LOW MEMORY(No leak).
[self.navigationController pushViewController:[[MainListController alloc] init:self] animated:NO];
#interface MainListController : UIViewController
...
- (id)init: (id)ref;
when i call on init function the dealloc of controller i was :
[ref dealloc];
i've this error :
objc[70754]: FREED(id): message isEqual: sent to freed object=0xe216b0
Program received signal: “EXC_BAD_INSTRUCTION”.
(void)dealloc {[super dealloc];}

You cannot (and should not) release/dealloc a parent view controller when pushing a new one onto the navigation stack. You can unload the view by responding to the didReceiveMemoryWarning message.
There are several other problems with your code:
Never ever call [obj dealloc] manually. Always use [obj release].
Your init method name should be more descriptive as to not conflict with the predefined init method. You should also (possibly) strongly type the ref argument if you need to use it. Something like (id)initWithParent:(UIViewController*)ref would be better.
Your code is leaking a MainListController object, since you are alloc/init'ing it and then handing it to navigationController. Change your code to [[[MainListController alloc] initWithParent:self] autorelease].

No, you can't dealloc UIViewControllers that are not visible. What happens when the controllers on top pop off the navigation controller? What would the OS display then?
Instead you should implement the didReceiveMemoryWarning method in all your controllers. These should release (not dealloc) as much cached data as possible. Anything that you can recalculate or bring back in from disk should be considered.
This is better than just deallocing views that are not visible as you really don't know how much memory is available in advance. On an iPhone 3GS you might have plenty of memory left even when using 40Mb.

Related

Would a UIViewController currently in UINavigationContoller's viewController stack be unloaded?

Also would anybody tell me what's the difference between viewDidUnload and dealloc?
viewDidUnload : called during low-memory conditions when the view controller needs to release its view and any objects associated with that view to free up memory. More
dealloc: Deallocates the memory occupied by the receiver, An object’s dealloc method is invoked indirectly through the release NSObject protocol method. More
Yes, it could be unloaded if a memory warning occurs.
As for the difference between viewDidUnload and dealloc - the former is called when your view is unloaded, typically because of a low memory situation. The latter is called when your object's retain count reaches zero (i.e. it is completely released from memory)
UIViewControllers are never unloaded. The UIViews they own can be.
So, if you question is if a UIView can be unloaded although its controller has been pushed on to the navigation controller, the answer is yes. Only the currently displayed UIView will not be unloaded (if you don't prevent the unloading mechanism from working).
Furthermore, viewDidUnload is a message that is sent to a UIViewController when the view it manages has been unloaded, which usually is not the same as deallocating the view. In fact, when a view is actually deallocated, it is unloaded for sure, but viewDidUnload is not sent.
A UIViewController that has been pushed onto a nav controller stack, and hasn't yet been popped, will not be dealloc'd. However, its view property may be unloaded -- in particular, if a low memory condition occurs AND the view for that view controller isn't currently visible (something is covering it, like a modal dialog, or another VC pushed on top of it), the view may be unloaded by the system.
viewDidUnload is a bad name for what the method does. It is called when a low memory condition caused the view to be unloaded -- i.e. it is not the 'opposite' method to viewDidLoad, which I think you might reasonably expect.
More info:
When should I release objects in -(void)viewDidUnload rather than in -dealloc?
Also important is that viewDidLoad will be called again after viewDidUnload. If you perform setup in viewDidLoad, you should deal with it in such a way that a second call to it will not cause memory leaks.
Either tear everything down in viewDidUnload (polite, if they are memory intensive), or check for their existence when you set them up and don't do it twice. (And, of course, totally tear them down before or during the dealloc method.)
You are not guaranteed that viewDidUnload will be invoked before dealloc is.

iPhone, method returns an objective-c object with a +1 retain count

I kind of understand why I'm getting this analyzer warning. Because I'm using an object that is being passed in. I've tried autorelease and retain however these cause me other problems like unrecognized selector sent to instance.
The aim of my CommonUI function is to re-use code, but I have to cater for addSubView and presentModalViewController.
Perhaps I'm doing some obvious wrong ?
Change your code like this:
HelpViewController *helpvc = [[HelpViewController alloc] init....];
[vw addSubview:helpvc.view];
[helpcv release];
I think you don't need to pass the other VC.
There are two problems here.
First, if you call [vc release] (as the other answers suggest), you'll certainly make the analyzer happy but likely crash the app. A view controller's view doesn't retain the controller, so any button targets in the view will be pointing to garbage.
You will need to somehow keep the HelpViewController retained for as long as it is showing up onscreen. The "parent" view controller should likely retain it somehow. You could autorelease it, and return it. Then whomever calls showHelpClick... would retain the returned controller.
Second, you don't need to have the (UIViewController *)vc passed in as an argument.

Why is viewDidUnload called less often than viewDidLoad?

I put NSLog(#"%#::%#", [[self class] description], NSStringFromSelector(_cmd)); in both viewDidLoad and viewDidUnload of a view controller.
In the log, I found viewDidLoad is called a lot more than viewDidUnload when the app moves to and from different .nibs.
Why?
The viewDidLoad and viewDidUnload is not corresponding to each other.
The viewDidUnload will only be called when you receive a memory warning. The system then will automatically call your viewDidUnload.
In the normal case, when you push a MyViewController and pop it out. The life cycle will happens like this:
init
viewDidLoad
release
That means, whenever you init and push/present a view, a viewDidLoad will be called. But when you pop the view, the release will be called in normal case and viewDidUnload will be called in memory warning case.
This is quite implicit and Apple doesn't state it clearly on the Guide. Here is some reference: Load and Unload cycle
I imagine that in the cases where -viewDidUnload wasn't called, the view controller was released.
viewDidLoad: controller loads view
viewDidUnload: memory warning, controller unloads view
viewDidLoad: controller loads view again
-: controller gets released, doesn't explicitly unload the view
You and up with 2 -viewDidLoad calls and 1 `-viewDidUnload' call.
Maybe also put a NSLog into the -dealloc method and see if the number of -dealloc and -viewDidUnload calls combined matches the number of -viewDidLoad calls.
when a new view loads, the old view can still be loaded in the background.
you are searching for viewWillAppear as conterpart i think.
views only unload in case of a memorywarning.

how to know whether dealloc is getting called or not in iphone sdk?

i am using UIviewcontroller subclasses. In my main view i have 3 buttons, each button will load a different nib. and each new nib is having one back button to come back to main view.
when i click one the back button of any view to move to the main view the dealloc of that view is not getting called? i didnt understood this.
can anyone explain when those views dealloc will be called?
if the dealloc method hasn't been called, it means that your retained your viewController object by hands. for example, in this case dealloc will not be called after clicking back button to return
MyViewController *controller = [[MyViewController alloc] init];
[self.navigationController pushViewController:controller animated:YES];
You should add
[controller release];
to this code to be sure that your instance of viewController will be deallocated. If you are absolutely sure, that you had sent equal number of alloc(or any message that increases object's retainCount) and release messages for your object and dealloc method doesn't be called anyway, it will be more complex. I hope that this answer will help. If you will find that your situation is "more complex", post a comment, then I'll try to explain with more details.
I too would like to dive deeper into understanding memory management details (below surface level) where it comes to controllers being pushed on and off of the stack. I built my framework from the text, "Beginning iPhone 3 Development" by Mark and LaMarche, but that text effectively re-uses sub-controllers and their dealloc methods never get called.
I have noticed that repeated use of a sub-controller with a NIB containing a UIWebView that calls Google's web directions url ... eventually results in a memory warning and my data is lost. This involves repeated "reuse" of the sub-controller.
If you can point me as well to in depth text that goes into nav controller and sub view memory management, that would be excellent.

When should I release objects in -(void)viewDidUnload rather than in -dealloc?

What is the -(void)viewDidUnload is good for?
Could I not just relase everything in -dealloc? If the view did unload, wouldn't -dealloc be called anyway?
In addition to what has already been indicated, I wanted to elaborate more about logic behind -viewDidUnload.
One of the most important reasons for implementing it is that UIViewController subclasses commonly also contain owning references to various subviews in the view hierarchy. These properties could have been set through IBOutlets when loading from a nib, or programmatically inside -loadView, for instance.
The additional ownership of subviews by the UIViewController means that even when its view is removed from the view hierarchy and released to save memory, through which the subviews are also released by the view, they will not actually be deallocated because the UIViewController itself still contains its own outstanding retaining references to those objects as well. Releasing the UIViewController additional ownership of these objects ensures they will be deallocated as well to free memory.
The objects that you release here are usually recreated and set again when the UIViewController view is re-loaded, either from a Nib or through an implementation of -loadView.
Also note that the UIViewController view property is nil by the time this method is called.
As the documentation says:
It is called during low-memory conditions when the view controller needs to release its view and any objects associated with that view to free up memory.
In the same situation dealloc is not called. This method is only available in OS3 and above. Dealing with the same situation in iPhone OS 2.x was a real pain!
Update July 2015: It should be noted that viewDidUnload was deprecated in iOS 6 because "Views are no longer purged under low-memory conditions and so this method is never called." So, the modern advice is not to worry about it and use dealloc.
This is because you will typically set the #property as "(nonatomic, retain)" and as such the setter that is created for you releases the current object and then retains the argument i.e.
self.property = nil;
...does something along the lines of:
[property release];
property = [nil retain];
Therefore you are killing two birds with one stone: memory management (releasing the existing object) and assigning the pointer to nil (since sending any message to a nil pointer will return nil).
Hope that helps.
Remember that viewDidUnload is a method in the view controller, not in the view. The view's dealloc method will get called when the view unloads, but the view controller's dealloc method may not be called until later.
If you get a low memory warning and your view isn't showing, which will happen for instance about any time you use a UIImagePickerController to let the user take a picture, your view will get unloaded and will need to get reloaded after that.
Conclusion:
View Controllers have a view property. Typically a nib or piece of code adds other views to this view. This happens often inside a -viewDidLoad method, like this:
- (void)viewDidLoad {
[super viewDidLoad];
[self createManyViewsAndAddThemToSelfDotView];
}
in addition, a nib file may create a button and append it to the view controller's view.
On iPhone OS 2.2, when -didReceiveMemoryWarning was invoked from the system, you had to release something to free up memory. You could release the whole view controller's view if that made sense. Or just big memory-consuming contents in it.
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
// Release anything that's not essential, such as cached data
}
Now, in the new OS 3.0, there is an -viewDidUnload method, which will be invoked from the system when the view has been unloaded because of low memory (please correct me: when exactly does this get called?)
-viewDidUnload is used to release all objects that were owned both by the view controller itself and the view. The reason: If a view controller holds references to childs of the view, i.e. a button, the referenced child views will not get released, because their retain count is >= 1. After they are released in -viewDidUnload, they can get freed up from memory.
Apple deprecated viewWillUnload, now you shoud use didReceiveMemoryWarning or dealloc to release your objetcs.
In iOS 6, the viewWillUnload and viewDidUnload methods of
UIViewController are now deprecated. If you were using these methods
to release data, use the didReceiveMemoryWarning method instead. You
can also use this method to release references to the view
controller’s view if it is not being used. You would need to test that
the view is not in a window before doing this.
If the view controller is popped from the navigation controller stack and is not retained anywhere else, it will be deallocated, and dealloc will be called instead of viewDidUnload. You should release the views created in loadView in dealloc, but it is not necessary to set the variables to nil, because soon after dealloc is called the variables will no longer exist.
You can release any subviews you hold on to, for example that UIImageView you retained in your loadView method, or better yet the image that was on that UIImageView.