The dealloc method of my view controller class is not called when popped after being pushed with the following code:
self.playerViewController = [[VideoPlayerViewController alloc] init];
[self.playerViewController set_video:video];
[self.navigationController pushViewController:self.playerViewController animated:YES];
[self.playerViewController release];
However if I change the push code to the following, then my dealloc is called appropriately after the view controller is popped:
playerViewController = [[VideoPlayerViewController alloc] init];
[playerViewController set_video:video];
[self.navigationController pushViewController:playerViewController animated:YES];
[playerViewController release];
I thought I understood the use of dot notation/self, but obviously not. Can anyone explain the problem here?
Here is the property:
#property (nonatomic, retain) VideoPlayerViewController *playerViewController;
and here is the synthesize:
#synthesize playerViewController;
You are retaining twice.
self.playerViewController = [[VideoPlayerViewController alloc] init];
^ retain + 1 ^^^^^ retain + 1
But you only release one time.
To fix your memory management issue you could change the code to something like this:
self.playerViewController = [[[VideoPlayerViewController alloc] init] autorelease];
And many people say [self.foo release] is bad style. You should consider to replace it with [foo release]
Related
I want to allocate memory for the variable to which i have allocated already.for example
self.m_tabbarController = [[TabbarController alloc] init];
I have to change assigned view controller for above tabbar controller.so i have to release
the above and allocate the same tabbar with new controllers. how can I release and allocate
new one.If i do the following, gives crashes.
if(self.m_tabbarController != nil)
{
[self.m_tabbarController release];
}
self.m_tabbarController = [[TabbarController alloc] init];
but self variable must be deallcated in dealloc method.any help please?if i do like following also, it gives crash?
m_tabbarController = [[TabbarController alloc] init];
[self.window addSubview:m_tabbarController ];
[m_tabbarController release];
First release it. Assuming your synthesised property is retain, the implementation will handle the release for you:
self.m_tabbarController = [[[TabbarController alloc] init] autorelease];
In short, you cannot rely on some way to reinitialize an instance unless you implement some kind of reinitialization method in the class.
If that's a UIViewController, just create a new UIViewController because you would need to know a lot about an implementation, all subclasses, and all members/ivars to implement reinitialization correctly. Sometimes you can accomplish this via its public properties, sometimes you won;t be able to reinitialize an instance correctly.
One problem with reinitialization is that what you alloc may not be what's returned -- and you may not otherwise know what type you are dealing with specifically in all cases. Proper, exhaustive reimplementation of a complex type adds a lot of implementation (which tends to be transitive too).
self.m_tabbarController = nil;
TabbarController *tempController = [[TabbarController alloc] init];
self.m_tabbarController = tempController;
[tempController release];
tempController = nil;
You should declare m_tabbarController with retain kind of property.
Now, modify your code as below:
TabbarController *temp = [[TabbarController alloc] init];
self.m_tabbarController = temp;
[temp release];
Also, release m_tabbarController into dealloc method.
[self.m_tabbarController release]; will release m_tabbarController not self so
if(self.m_tabbarController != nil)
{
[self.m_tabbarController release];
}
self.m_tabbarController = [[TabbarController alloc] init];
is absolutely fine
I have a view controller that was presented using
[self presentModalViewController:myVC animated:YES];
this VC has several declared retained properties (#property) that I have to release on its dealloc.
The variables are declared as
#property (nonatomic,retain) myClass1 *myProperty;
#property (nonatomic,retain) myClass2 *myProperty2;
// etc... and then synthesized on .m
The problem is that when I dismiss the viewController using
[self dismissModalViewControllerAnimated:YES];
it crashes on the dealloc, when releasing the retained properties I have declared, with the error *modifying layer that is being finalized *
Apparently the the viewController is gone at the time its own dealloc runs and then it crashes.
How do I solve that? Thanks in advance.
edit
the code that presents the viewController is on the rootViewController and is this:
UIViewController *myVC = [[UIViewController alloc] init];
myVC.delegate = self;
UINavigationController *navigator = [[UINavigationController alloc] initWithRootViewController:myVC];
[self presentModalViewController:navigator animated:YES];
[navigator release];
[myVC release];
and this is the what the dealloc code on myVC contains
- (void) dealloc {
[myProperty1 release]; // see this properties at the beginning of this question
[myProperty1 release]; // if I comment these 2 relesases it stops crashing
[super dealloc];
}
myVC is dismissed from inside itself, but that's fine according to the docs. I have also tried to dismiss it from the rootviewController but it continues to crash. The only way to stop crashing is to disable the release lines on the dealloc.
How do you set the properties?
self.myProperty =
? My guess is that you do not retain them. Are you doing
myProperty = ...
by any chance, with neither a retain or self.? The setter you synthesize needs a chance to actually retain your newly created object...
So in full it should read something like this:
MyClass1 *aProperty = [[MyClass1 alloc] init];
self.myProperty1 = aProperty;
[aProperty release];
...i asked where you allocate and init "myProperty1" and "myProperty2"...
i'm afraid that you make confusion thinking that this:
#property (nonatomic,retain) myClass1 *myProperty;
#property (nonatomic,retain) myClass2 *myProperty2;
need that you release myProperty and myProperty2
well, you are wrong!
you are just declaring the kind of objects you are going to use, not allocating them
you need to release them just if you alloc them someWhere...
I am still learning the ropes of Objective C and iPhone development. My weak point is memory management - any help will be much appreciated.
In the code below, where can I release the NSMutableArray listOfViewControllers? Keep in mind the function createTabs can be called within the app multiple times and the tabs are recreated dynamically based on user input. This function is within a ViewController.
If i do [listofViewControllers release] just before exiting the function, the app crashes when I have to call createTabs again
If I use a convenience method like below:
NSMutableArray *listOfViewControllers = [NSMutableArray arrayWithCapacity:1]
instead of:
NSMutableArray *listOfViewControllers = [[NSMutableArray alloc] init]
it still crashes when createTabs is called again
-(void) createTabs
{
//TODO - memory management - where do you release this?
NSMutableArray *listOfViewControllers = [[NSMutableArray alloc] init];
if ([briefingsArray count] > 0)
{
//add briefing(s) tab(s)
for (Briefing *briefing in briefingsArray)
{
WebViewController *briefingViewController = [[WebViewController alloc] initWithBriefing: briefing];
[listOfViewControllers addObject:briefingViewController];
[briefingViewController release];
}
[listOfViewControllers addObject:alertViewController];
//add archives tab
NSString *archiveURL = [NSString stringWithFormat: ARCHIVEURL, DeviceID()];
UIViewController *archiveViewController = [[WebViewController alloc] initWithURL:ARCHIVEURL andTitle:#"Archives" andImage:#"archive_icon.png"];
[listOfViewControllers addObject:archiveViewController];
[archiveViewController release];
}
NSArray *oldlistOfViewControllers = [self.tabBarController viewControllers];
UIViewController *vcOld = [oldlistOfViewControllers objectAtIndex:[oldlistOfViewControllers count] -1];
[listOfViewControllers addObject:vcOld];
[self.tabBarController setViewControllers:listOfViewControllers
animated:YES];
}
My best guess is that it has nothing to do with tab bar controller. When you did not release the array, the controllers in the array would never be dealloc and there was no problem at all. So it's likely that the problem might come from deallocation of your WebViewController.
It looks like what you are creating here - listOfViewControllers - should be an instance variable of whatever object you are making here. Then you should alloc/init it inside the object's -init method, and release it in dealloc.
It is good practice (and usually necessary) to make an instance variable for anything you expect to exist after the end (or before the start) of a function call.
After [self.tabBarController setViewControllers:listOfViewControllers
animated:YES];, you can release your listOfViewControllers. Because tabBarController will retain this listOfViewControllers by copy policy.
You can see the UITabBarController reference about viewControllers property. This property adopts the copy policy.
#property(nonatomic, copy) NSArray *viewControllers
I'm new to the memory management of the iphone and had a question about standards/correctness.
My header file declares:
IBOutlet UITabBarController *tabBarController;
#property (nonatomic, retain) UITabBarController *tabBarController;
In my init() code I was doing something like the following:
self.tabBarController = [[UITabBarController alloc] init];
[tabBarController release];
NSLog(#"Retain count of tbc: %d",[tabBarController retainCount]);
to get the retain count back to one. Is this correct from a standardization point of view? It just looked a bit different to me, but again I'm new to this.
Thanks
That's normal.
What you do:
self.tabBarController = [[UITabBarController alloc] init];
[tabBarController release];
maybe performed by compiler as:
id *tempVar = [[UITabBarController alloc] init];
self.tabBarController = tempVar; //till now, retainCount is 2
[tabBarController release]; //now, retainCount is 1
When you alloc it, this memory block will be retained by a temporary var. So a better way to do that is:
UITabBarController *tabCtl = [[UITabBarController alloc] init];
self.tabBarController = tabCtl;
[tabCtl release];
I'm not an expert of object-c, just have some knowledge about compiling. So, if I'm wrong, experts here please point out.
For assigning to the property, you should either use
self.tabBarController = [[[UITabBarController alloc] init] autorelease];
or
[tabBarController release];
tabBarController = [[UITabBarController alloc] init];
(Remember to release the previous value first)
The property setters/getters should be solely responsible for retaining/releasing the instance variable. What happens if you (or somebody else) changes the property setter to take a copy of the input instead of retaining it? In that case you are going to over-release the instance variable and leak the original object.
You are essentially sending a message which has private side-effects, and then using knowledge of those private details by releasing the instance variable on the next line. i.e. your code is the same as:
[self setTabBarControler:[[UITabBarController alloc] init]];
/* Relying on knowledge of the instance variable is bad here, setTabBarController
might do something different in the future */
[tabBarController release];
Even though you are in full control of the class, you should still adhere to the basic principles of abstraction and encapsulation. Leave the retaining/releasing of instance variables to the underlying property implementation.
Why not
tabBarController = [[UITabBarController alloc] init];
?
You could do it this way, but better is to not use this implicit setter syntax in your init() method (because you might override the setter and do further stuff that might not work yet if the object is not fully initialized).
Just do:
tabBarController = [[UITabBarController alloc] init];
In my AppDelegate I initiate a tabBar Controller, to which a bunch of navigationController is added as tabs. I use the following code:
// Init tabBar Controller
tabBarController = [[[UITabBarController alloc] init] retain];
// Init Root Views of navigation controllers
FirstRootViewController* firstViewController = [[[FirstRootViewController alloc] init] autorelease];
SecondRootViewController* secondViewController = [[[SecondRootViewController alloc] init] autorelease];
ThirdRootViewController* thirdViewController = [[[ThirdRootViewController alloc] init] autorelease];
// Init Navigation controllers of tabs
UINavigationController* firstNavController = [[[UINavigationController alloc] initWithRootViewController:firstViewController] autorelease];
UINavigationController* secondNavController = [[[UINavigationController alloc] initWithRootViewController:secondViewController] autorelease];
UINavigationController* thirdNavController = [[[UINavigationController alloc] initWithRootViewController:thirdViewController] autorelease];
firstNavController.navigationBar.barStyle = UIBarStyleBlack;
secondNavController.navigationBar.barStyle = UIBarStyleBlack;
thirdNavController.navigationBar.barStyle = UIBarStyleBlack;
// Create array for tabBarController and add navigation controllers to tabBarController
NSArray *navigationControllers = [NSArray arrayWithObjects:firstNavController, secondNavController, thirdNavController, nil];
tabBarController.viewControllers = navigationControllers;
[window addSubview:tabBarController.view];
And the dealloc function:
- (void)dealloc {
[window release];
[tabBarController release];
[super dealloc]; }
firstNavController are the navigation controllers to be added which are properly released altogether a few lines later (they are created using alloc).
TabBarController is a class variable which has been created using #property (nonatomic, retain) and #synthesize tabBarController. It receives a release command in the dealloc method.
Now instruments tells me that I have two memory leaks on the line with "tabBarController.viewControllers = navigationController".
I have tortured my head, yet I don't see why: From my understanding, navigationControllers should get released automatically and if I send it a release command a few lines later, the app crashes, so I guess I am right.
Any guesses whats wrong?
Thanks a lot!
Firstly, your tabBarController class variable has it's reference count increased twice. Once from the alloc and once from the retain in the first line of your code, yet is only released once in dealloc This is probably where your memory leak is coming from.
Secondly, although you have declared a matching #property(nonatomic, retain) tabBarController (and implemented via #sysnthesize) you are not actually using the property accessors (and its corresponding retain & release behaviour during assignment) To do this you need to use self.tabBarController rather than just tabBarController which will refer to the class variable, not the property.
Try modifying your code to the following to see if this solves your problem
// Init tabBar Controller
UITabBarController* tbc = [[[UITabBarController alloc] init];
self.tabBarController = tbc;
[tbc release];
...
- (void)dealloc {
[window release];
self.tabBarController = nil;
[super dealloc]; }