UITableView leaking? - iphone

I have a UITableViewController and I set some properties in the viewDidLoadMethod like so:
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithTitle:#"Done" style:UIBarButtonItemStyleDone target:self.parentViewController.parentViewController action:#selector(dismissSettings)] autorelease];
[self setTitle:#"Gabbai Settings"];
//Set up the table
[self.tableView initWithFrame:self.tableView.frame style:UITableViewStyleGrouped];
[self.tableView setRowHeight:65.0];
[self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleSingleLineEtched];
[self.tableView.backgroundView setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:#"%#_settings", kTheme] ofType:#"png"]]]];
}
The app shows a UIScrollViewController and a UIButton. When the button is pressed, the app displays a modal UINavigationController and that UINavigationController contains a UITableViewController.
For some reason, Leaks reports some leakage when I show the UITableViewController. However, if I comment out the four lines after //Set up the table, everything is fine.
When the four lines are uncommented, the Leaks instrument shows the following:
I'm not sure what is going on here, but it's really annoying. I've used the same four lines of code before to customize my UITableViewController and this is a new behavior.
What could be wrong?

Explicitly release tableView in your dealloc method and see what happens.
Or better yet, clean all -> Build and Analyze, tell us what you see

As has been pointed out by other answers, your problem is the line:
[self.tableView initWithFrame:self.tableView.frame style:UITableViewStyleGrouped];
It will create a new UITableView object and it will not modify self.tableView which means that line is totally pointless. It only creates the leak you are experiencing. Remove it and you should be fine.

if self.tableview already exists, you don't want to initialize it again. Either initialize it once (which I'm guessing you already did, maybe by loading from a nib) and then if need be, reset the frame here.
Or just alloc/init the tableview here.

Maybe you can try defining the uiBarButtonItem as a variable, then assign it to the navigation left bar button item and then release the button
Have you try build & analyze under the Build menu? With 2.0 Objective C sentences its pretty accurate
in addition, you have to be careful with property definition, you are using self.tableView, I assume you you have something like #property(nonatomic, retain)?, in that case, once you alloc, you should release the property in the next line..
Finally, this line is extremely weird: [self.tableView initWithFrame:self.tableView.frame style:UITableViewStyleGrouped]; you are trying to initialize a table thats already initialized, because if you don't, self.tableView.frame should be in error. In addition to that, the initWithFrame method returns something that is not being assigned.. I think that you can think a better way to do this
Sorry about the mess, I've been answering this question in the chat, but unfortunately you were disconnected.
Hope this helps.

Looks like you have an array or dictionary thats leaking, not the tableview.
What is the array that you are using to fill your tableview?
Also, you wont want to [self.tableVIew initWithFrame,
try [self.tableView setFrameCGRectMake(x,y,w,h)];

Related

How to release subviews

In my iPhone/iPad app,
I am adding one subview to my main view.
This subview has one imageview and button.
When to release them ?
My code is here,
customAlertView=[[UIView alloc] initWithFrame:CGRectMake(0, 0, 600, 600)];
UIImageView *imgv=[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"celebration.png"]];
UIButton *btnOK=[UIButton buttonWithType:UIButtonTypeCustom];
[btnOK setTitle:#"OK" forState:UIControlStateNormal];
[btnOK addTarget:self action:#selector(alertOKClicked) forControlEvents:UIControlEventTouchUpInside];
[customAlertView addSubview:btnOK];
[customAlertView addSubview:imgv];
[self.view addSubview:customAlertView];
[imgv release];
[btnOK release];
In one another method I am writing the code.
[customAlertView removeFromSuperview];
My confusion is imageview and button is there If
I release the customalertview here will it releases its subviews automatically.
If yes then no problem.
If NO how to release it
as I have done here released the objects immediately after adding subviews.
It will cause my OK button Unworthy. And will not affect the button click.
So, On removing from superview should I write.
[[customalertview subviews] release];
Your code is correct.
You release them after you've added them to the alert view, as the alert view takes care of retaining them. When you call removeFromSuperview, it'll get released automatically.
I think the points you are missing, based on your comments on the existing answers, are the following:
A view retains its subviews - so if you create a new view object, and add it as a subview to something else, you can then safely release it, unless you'd like to keep a reference around for it yourself.
When a view is removed from its superview, it is released. So if there are no more objects retaining it, it will be deallocated.
When a view is deallocated, it will automatically release all of its subviews, and so on down the tree.
Enable ARC as soon as you are able to.
You are doing it the right way. The customalertview will releases its subviews automatically.
Your object will be released when the release count go to 0, that means in the theory, and if you are coding well, that this object does not have any reference to it anymore.
While you maintain your custom alertView in your view, you have an object retaining your things, so the release count will not be 0 until you remove the customAlertView, because you have added they to the customAlertView, and when you remove the alert, the alert will be released, and all the things that it is retaining will be released too.
Hope it help you to understand how things work.
If you want to know more about memory management you can take a look at apple documentation here
EDIT:
I forgot to mention that you will need to release your custom alert too after you remove it.
If you do not understand the memory management you also can take a look at: http://cocoadevcentral.com/d/learn_objectivec/ section 7

Alloc - add as accessoryView - release: does it leak?

Does this leak memory? This code is executed in cellForRowAtIndexPath: outside the cell creation block (so each time the table cell is updated).
MyView *myView = [[MyView alloc] init];
// ... configuration code
cell.accessoryView = myView;
[myView release];
Or in other words, will the UITableViewCell release the object in its accessoryView when a new object gets assigned to it?
Thanks.
Yes, the cell will release the accessory view and you do not have a leak in the example.
The property accessoryView of a UITableViewCell is a retain type, in common with many view properties in the kit. Check the Apple documentation for UITableViewCell to convince yourself of this. Therefore there will be no leak in your example - the retain count has been correctly managed. You've also correctly released after setting the accessory view, on account of your alloc call.

how to release UIVIewController after remove his view

How to release view controller created like this:
VCClass *vc = [[VCClass alloc] initWithNibName:#"VCClass" bundle:nil];
[self.view addSubview:vc.view];
so the view appear, UIViewController is allocated. Now I want to releas it from within VCClass. I call inside VCClass:
[self.view removeFromSuperView];
my question is, where should I release "vc" object attached to removed view. Is there a good way to notify viewcontroller that is can be released while view is released ?
addSubview does a +1 to the retain count, and it's usually a good practice to release as soon as you don't need it, and you're handing it to another pointer. It's like a glass ball, it is passed hand by hand, and if no one is holding, it falls to the ground and breaks.
Example:
UIView *sampleView = [[UIView alloc] init]; // Retain count: 1
[self.view addSubview:sampleView]; // Retain count: 2
[self.view release]; // Retain count: 1
When the removeFromSubview: is called, the object will be released:
[sampleView removeFromSuperView]; // Retain count: 0
That's for memory management.
Answering your question, a safer way to do what you want to do (loading just a part of an ViewController from a nib (I'm assuming you're using a nib, because you used #"VCClass" in the initWithNibName:), is to use it as following:
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"VCClass" owner:self options:nil];
UIView *view = (UIView*)[nib objectAtIndex:0];
This works by loading the NibName into memory, and then stealing the first element (if you only have a UIView inside, then it will pick that, as the top-most element). This is done similarly for UITableViewCells when loading them from nib files. Nib Files are autoreleased, and it makes more sense, since you apparently just care about the view itself, not the controller.
After you remove it, add a call to
[self autorelease];
Views don't know about their view controllers except as a weak reference to a delegate. This is to avoid a circular reference, among other reasons. VCs often have a life outside their views - hence, the viewDidLoad and viewDidUnload messages. For example, throughout the lifetime of a tab-bar application, the VCs for each tab might go through many different view instances while never being deallocated. Therefore, you should avoid having the view release its own view controller.
Often, the class that allocated the VC should be the one to release it. In the code you provided, you have:
VCClass *vc = [[VCClass alloc] initWithNibName:#"VCClass" bundle:nil];
[self.view addSubview:vc.view];
The controller class that the above code is in is probably the place best suited to releasing the VC. You might need to devise a delegate call just for this purpose.
[self.view removeFromSuperView]; should release your said view from the memory. Though be warned that this will not be true if your view has been retained by any other object that is its retain count is more than 1. Also look at the second answer on this thread.
Does UIView's removeFromSuperView method remove the UIView from memory

Back and forth, removeFromSuperView

Im a bit confused...
I have a mainview, which by the click of a button shows a subview. What I want to do next is to
be able to switch back and forth between the Main and the Sub, but when I do this, the return button FROM the subView makes the TO SubView button disabled...I cant seem to be able to access the Subview a second time. Nothing happens.
What I have is a UIButton, and an IBAction, which I have written the "[self.view removeFromSuperView];" in.
Please do not get me wrong here, I do get back to the mainView. The problem is that I cant go back to the subview afterwards.
I've read something in the documentation about retaining the subView...But I did not quite understand how to do it.
Could anyone please shed some light over this?
Thanks!
this is just a guess, since you don't provide much code:
- you might first need to retain the view. in case it's only retained by its current superview
[self.view retain];
remember to free it manually when it's no longer needed.
[self.view release];
Why dont you try out this?
to open ur subview:
Ursubview *Ursubview =[[Ursubview alloc] initWithNibName:nil bundle:nil];
Ursubview.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentModalViewController:Ursubview animated:YES];
to go back:
[self dismissModalViewControllerAnimated:YES];
Why not just hide it instead of removing it?

iOS / Xcode 4: View won't load

This is really frustrating as I've tinkered with previous versions of Xcode and have done this before but playing around with a new app now, it's not working for some reason.
I have the app open to a UITableView and want it to load to a detail UIView once I select a cell. However, when I choose a cell in the iPhone simulator, it just highlights the cell blue and doesn't load the view.
Here is the code I'm using the the RootViewController:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
WorkoutViewController *workoutViewController;
workoutViewController = [[WorkoutViewController alloc] initWithNibName:#"WorkoutViewController" bundle:nil];
workoutViewController.workoutName = [workouts objectAtIndex:indexPath.row];
[self.navigationController pushViewController:workoutViewController animated:YES];
[workoutViewController release];
workoutViewController = nil;
I have the view linked to the File Owner in the WorkoutViewController.xib file. When I put in a breakpoint at #implementation WorkoutViewController, it does get to that breakpoint but it goes to the #synthesize line and then jumps right back out to [self.navigationController ...etc]; and never returns back to the WorkoutViewController.m file.
I would guess that you didn't set the ViewController to be the TableView's delegate. To check, open your ViewController xib-file and rightclick FilesOwner. Under Referencing Outlet you would usually have both delegate and data source" connected to your TableView. If that is not the case, drag New Referencing Outlet to your TableView.
If I'm wrong and they are all connected, you might want put a breakpoint at the beginning of your didSelectRowAtIndexPath method. Does the debugger stop there, once you select a row?
It might also be worth mentioning that a breakpoint at #implementation usually doesn't make much sense, you would rather want to place it in a method like init. Also, even though you are using Xcode 4 now, this is unlikely to be the cause of your problem, it looks more like an implementation issue.
Hope this helps, if you need further help just let me know!
Doh! Problem resolved. I had forgotten to actually put the RootViewController into a navigation controller on the MainWindow.xib. Appreciate the responses.