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
Related
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]
Part of my code presents a UITableViewController in the following way:
FlipsideViewController *controller = [[FlipsideViewController alloc] initWithNibName:#"Settings" bundle:nil];
flipside = [[UINavigationController alloc] initWithRootViewController:controller];
controller.delegate = self;
flipside.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:flipside animated:YES];
[flipside release];
[controller release];
Using the leaks tools, no memory leaks are picked up on. However, whenever I bring up the settings menu (as shown in the code above), more memory appears to be allocated and never released - almost 100 kB every time.
Weirdly, the inclusion of the two release statements at the end seems to have no effect on the memory allocation..? Is there something I am misunderstanding about memory allocation in objective-c, or is something weird going on?
Any ideas are much appreciated - thanks!
If flipside is a retained property then the navigation controller is leaking. the problem is that you are bypassing the accessor method and releasing flipside directly. This is just messy code. A better way to do it would be to make an accessor method for flipside that will only alloc a new one if you haven't already created one. It's called lazy loading. To do this, just leave the #synthesize for flipside (but you shouldn't set it from outside the accessor method), in your header file change the property to, and add this method to the implementation:
- (UINavigationController *)flipside {
if (flipside != nil) {
return flipside;
}
FlipsideViewController *controller = [[[[FlipsideViewController alloc] initWithNibName:#"Settings" bundle:nil];
controller.delegate = self;
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:controller];
[controller release];
navController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
// This implies a retain if your flipside property is set to retain
self.flipside = navController;
[navController release];
}
make sure to put self.flipside = nil in the viewDidUnload method of the view controller the code you included came from (I assume it's a presentSettings action).
what your presentSetting action should now look like is this:
- (IBAction)presentSettings {
// make sure you use the accessor self.flipside instead on accessing the variable directly
[self presentModalViewController:self.flipside animated:YES];
}
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
my image picker is initialized like:
self.imgPicker = [[UIImagePickerController alloc] init];
self.imgPicker.allowsEditing = YES;
self.imgPicker.delegate = self;
self.imgPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
presentation:
[self initImagePickerFromLibrary]; ----(this calls the lines I have mentioned before)
[self presentModalViewController:self.imgPicker animated:YES];
[imgPicker release];
apple instrument says:
before calling the picker memory used is 3 Mb.While the picker is in function 12Mb.While editing image is 28Mb and my app crashes.Anyone did find a solution for this?
The one thing that comes to mind is that you're doing self. which may mean that your image picker is retained twice. Once, because you're allocating it and once because you're using a setter.
What does the #property line look like for imgPicker? Does it have retain? If it does, you should either change the first line in your first quote above to:
imgPicker = [[UIImagePickerController alloc] init];
I.e. removing self..
Also in your second line, you're releasing imgPicker directly. If your #property does have retain, you should instead just do:
self.imgPicker = nil;
The reason is that the #property synthesizing retains and releases objects when you set them. If you release the imgPicker without setting it to nil, and then, later on, try to set it to a new value, the system will attempt to release the already released object, and probably crash. The above is the same as doing:
[imgPicker release];
imgPicker = nil;
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];