Below is the code in which i have some doubts:-
MyController *vc= [MyViewController alloc] initWithNibName:#"myController"
bundle:nil];
[self.navigationController pushViewController:vc animated:YES];
[vc release];
Then, i pop my controller by pressing the back button on nav bar.
The problem is memory is increased by 5mb(On Activity Monitor) for the first time.And when i pop the controller it doesnt get released.
And when i do the push and pop again and again the memory increases by small amount and decreased too.
UIView *myView=[UIView alloc]init];
self.vi=myView;
[myView release];
UIScrollView *mySv=[UIScrollView alloc]init];
self.sv=mySv;
[mySvrelease];
UIProgressView*myPv=[UIProgressViewalloc]init];
self.pv=myPv;
[myPvrelease];
UIWebView *myWv=[UIWebView alloc]init];
self.wv=myWv;
[myWv release];
-(void)dealloc
{
[wv relase];
[sv release]
[pv release];
[vi release];
[super dealloc];
}
wv,sv,pv,vi are MyViewControoler variables which have retain attribute.
I wrote this code to check the memory management concepts,but iam confused now seeing the activity monitor and instruments results.
I have verified that no object is getting leaked in my MyController class by using Instruments on it.
MyViewController have a content which does a leaks
Its not a memory leak. iOS cache the controllers you have visited recently. It will get deallocated by iOS itself when your application needs memory to execute some other tasks.
try this method in MyViewController.m file
- (void)dealloc
{
//release any object thats retained into the memory
[super dealloc];
}
Related
I was thinking about this today, and now i've tested i'm a little confused…
When using viewControllers either by pushing a viewController onto the Navigation Stack or Presenting a ViewController modally I'm wondering about memory management.
Lets use the modal example as a thought experiment, here is the source to create and present the view, in my example it doesn't matter if ARC or not so here's both:
With ARC:
ViewController *myViewController = [[ViewController alloc] init];
myViewController.delegate = self;
[self presentViewController:myViewController animated:YES completion:NULL];
Without ARC:
ViewController *myViewController = [[ViewController alloc] init];
myViewController.delegate = self;
[self presentViewController:myViewController animated:YES completion:NULL];
[myViewController release]; //As it's now 'owned' by the presenting View controller
This would be my understanding about how to present a viewController modally over an existing ViewController.
Lets say for our example the above code resides in a method which is called when a button is touched to present the ViewController.
Now to my question,
What I am doing is calling this code each time a button is touched, During testing with Instruments I didn't seem to have any leaks. - However because I have NSLog statements in the myViewController dealloc & viewDidLoad methods I know that it's getting instanciated everytime I touch the button but never deallocated.
So...
A) Why am I not getting a leak showing (or a rise in Live Bytes) in instruments (when either using ARC or not) because I am seemingly creating a new viewController and leaking the old one each time I go to present it.
B) What is the correct way to write the above code if this is not memory safe? I see this kind of code snippets all over Apple's example code and internet. Should I (and they) not be wrapping the alloc init line in an if statement to check if the object is already created?
i.e.
if(!myViewController)
{
ViewController *myViewController = [[ViewController alloc] init];
}
myViewController.delegate = self;
[self presentViewController:myViewController animated:YES completion:NULL];
Thanks for taking the time to read and answer, I really wonder about this as I've been creating, pushing and presenting ViewControllers using the above code the whole time, and never noticed a leak! - might have to go back and rewrite it all!
To avoid confusion please note: The delegate property is a custom property of my UIViewController subclass (where I've implemented a delegate protocol), required to dismiss the Modally present Viewcontroller properly. As per coding guidelines.
Regards,
John
EDIT As Requested, Creation of the delegate:
.h
#protocol NotificationManagementViewControllerDelegate;
#interface NotificationManagementController :
{
__weak NSObject <NotificationManagementViewControllerDelegate> *delegate;
}
#property (nonatomic, weak) NSObject <NotificationManagementViewControllerDelegate> *delegate;
#protocol NotificationManagementViewControllerDelegate <NSObject>
#optional
- (void)didFinishSettingNotification:(NotificationManagementController *)notificationManagementController;
.m
- (void)sendMessageToDismiss {
if ([[self delegate] respondsToSelector:#selector(didFinishSettingNotification:)]) {
[self.delegate didFinishSettingNotification:self];
}
}
And finally in the delegates .m:
- (void)didFinishSettingNotification:(NotificationManagementController *)notificationManagementController
{
[self dismissViewControllerAnimated:YES completion:NULL];
}
You are not getting a leak because you create a new controller and ARC will release this allocation for you.
But, it's better to create a #property for your new view controller.
and modify your i.e. implementation like :
#property (nonatomic, strong) ViewController *myViewController;
if (!_myViewController)
self.myViewController = [[ViewController alloc] init];
self.myViewController.delegate = self;
[self presentViewController:_myViewController animated:YES completion:nil];
Here, you have a lazy property and you don't create a new one ViewController after the first creation.
But, you need to pass your delegate (or any property) outside your test.
Furthermore, if you use your first implementation and add this controller in a subview of the current controller without property, this will work but you will get a leak.
I got this experience with the code below :
RootViewController
- (void)viewDidLoad
{
[super viewDidLoad];
ViewController *myViewController = [[ViewController alloc] init];
[self.view addSubview:myViewController.view];
}
myViewController will be add on the screen but released immediately without keeping any reference of the object, so if you add an action in 'ViewController`, your application will crash without explanation of XCode.
So, the correct way to write this without leak will be :
- (void)viewDidLoad
{
[super viewDidLoad];
if (!_myViewController)
self.myViewController = [[ViewController alloc] init];
[self.view addSubview:self.myViewController.view];
}
The answer is a bit longer and can be improved so don't hesitate !
Hope it's going to help some people.
I have a problem with my application. I have 18 views but when you view every time step consumes more memory. After the application is crash.
while ([self.view.subviews count] > 0) {
[[self.view.subviews lastObject] removeFromSuperview];
}
[self presentViewController:[[proj_lletrac_14_ontroller alloc] init] animated:NO completion:nil];
[proj_lletrac_14_Controller release];
[proj_lletrac_13_Controller release];
This code is a small example
My english is bad, I speak spanish :)
Thanks
The problem is your passing in an allocated object and not releasing it. You need to have it in a variable so you can release it:
proj_lletrac_14_ontroller *viewController = [[proj_lletract_14_ontroller alloc] init];
[self presentViewController:viewController animated:NO completion:nil];
[viewController release];
So in steps your allocating an instance to a variable:
proj_lletrac_14_ontroller *viewController = [[proj_lletract_14_ontroller alloc] init];
Passing the instance to the presentViewController method:
[self presentViewController:viewController animated:NO completion:nil];
Now you don't need to worry about the instance so you release your allocated object:
[viewController release];
Simple memory management.
Never allocate an object when passing in to functions unless you stick it in an autorelease pool:
[self presentViewController:[[[proj_lletrac_14_ontroller alloc] init] autorelease] animated:NO completion:nil];
But this is bad memory management practice. You should release everything you know that you don't need again.
I am using a class inherited from UINavigationController present as a modal view, in the navigation bar I have a button 'Done' which will dismiss the modal view when user tap on it. Everything behave normal except the dealloc() in ImagePickerController, GroupPickerController (which is initialized as root view) not get called when I dismiss the modal view. This cause the leak of the memory.
Here is the code use it:
ImagePickerController *picker = [[ImagePickerController alloc] initWithRootViewController:nil];
// don't show animation since this may cause the screen flash with white background.
[self presentModalViewController:picker animated:NO];
picker.navigationBar.barStyle = UIBarStyleBlack;
[picker release];
Here is what's inside ImagePickerController, which is a UINavigationController:
- (id)initWithRootViewController:(UIViewController *)root {
GroupPickerController *controller = [[GroupPickerController alloc] initWithNibName:nil bundle:nil];
self = [super initWithRootViewController:controller];
[controller release];
if (self) {
self.modalPresentationStyle = UIModalPresentationPageSheet;
}
return self;
}
- (void)dealloc {
[super dealloc];
}
-(void) dismiss
{
[self.navigationController setViewControllers:nil];
[self dismissModalViewControllerAnimated:YES];
}
Here is the code in GroupPickerController, it response to a button in the navigation bar, to dismiss the modal view:
...
#pragma mark - button actions
- (void)done {
[self.parent dismiss];
}
I tried to manually remove the views from NavigationController, seemed not no effect at all...
[self.navigationController setViewControllers:nil];
Thanks for the help!
UPDATED:
Please disregard this question, apparently it's a mistake. :(
Finally get the problem solved... not change any of the code, but a rebuild the project. :(
First of all, you should not be subclassing UINavigationController:
This class is not intended for subclassing.
What does this line do?
controller.parent = self;
If the controller retains the parent-property, you have a retain cycle which would cause the issue you are describing. Remember that all view controllers in the UINavigationController stack can access the navigation controller with the -navigationController property.
There's is a difference between a UIViewController begin dismissed and released.
When you dismiss it, it can be released at any moment, but not necessarily immediately.
Are you sure you have a memory leak ? Maybe the picker is released a few seconds after the dimiss.
If you really have a memory leak, that means there is another place where you picker is retained.
I am working on an application where i am pushing one view controller on to a UINavigationController and releasing it immediately as the navigation controller retains it.When i am poping the view controller the dealloc method is being called as expected but the problem is the app is getting crashed.If i observe in GDB by enabling NSZombie its saying that -[MyViewController isKindOfClass:]: message sent to deallocated instance 0x6847a00.If i remove [super dealloc]from my view controller's deallocmethod its working just fine.I have nothing else in dealloc method except [super dealloc].What could be the problem here, can any one please help.The code snippet is below:
MyViewController *myViewController = [[MyViewController alloc] initWithNibName:nil bundle:nil];
myViewController.path = selectedPath; //very important to set path here
myViewController.parentViewController = self;
[self cleanBookshelf];
[self.navigationController pushViewController:myViewController animated:NO];
[myViewController release];
[indicatorView removeFromSuperview];
[loadingindicator stopAnimating];
and i am poping in one action method of myViewController as
-(IBAction)goBack:(UIButton*)sender{
[self.navigationController popViewControllerAnimated:YES];
}
Just guessing, but I suspect that the problem is with this line:
myViewController.parentViewController = self;
UIViewController's parentViewController property is marked readonly, and I'd take that as a strong message that you shouldn't mess with it.
I used a Popover to display image in it. When the user touch a button, the popover appears with a slideshow inside.
I initialize the Popover like this : `
- (IBAction)showPopover:(UIButton *)sender {
myPopover *content = [[myPopover alloc] init];
detailViewPopover = [[UIPopoverController alloc] initWithContentViewController:content];
detailViewPopover.popoverContentSize = CGSizeMake(600., 400.);
detailViewPopover.delegate = self;
[detailViewPopover presentPopoverFromRect:sender.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
[content release];
}
`
detailViewPopover is a UIPopoverController, I declare it my .h.
I dismiss the Popover like this : `
- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController {
// If a popover is dismissed, set the last button tapped to nil.
[popoverController release];
}`
When I run my app, it works until I got "-[UIPopoverController release]: message sent to deallocated instance 0x1b29b0" and my apps crashes...
I understand I release too much time my UIPopoverController, but I don't know where. Is my implementation good ?
Thanks for your help
Let me know if you need more information, I will edit the post
You shouldn't release your popoverController here.
You need to call release on detailViewPopover in your current view controllers dealloc method
- (void) dealloc
{
[detailViewPopover release];
[super dealloc];
}