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

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.

Related

Confusion about UIView's setNeedsDisplay

I have an ivar of UITableView* myTableView. I have data being loaded from internet so when the data gets loaded should i call [myTableView setNeedsDisplay], i know i can/should call [myTableView reloadData] but the confusion is that calling setNeedsDisplay should also work but is not working.
I am just looking for an explanation as to what setNeedsDisplay does? when called on UITableView instance.
As per the documentation setNeedsDisplay calls drawRect in "next drawing cycle". so can anyone tell me what is the next drawing cycle.
setNeedsDisplay method has nothing to do with the reloading of the tableView. It just redraws the view of the tableView, not its cells or separators.
setNeedsDisplay and reloadData are entirely for different purposes.
setNeedsDisplay marks the calling UIView as needing to be redrawn is a purely visual sense, which as stated will happen on the next drawing cycle.
This is completely different to reloading the data when used in a UITableView context.
See this article for a little more information on the subject.
SetNeedsDisplay
A good example of this is when a UIImageView is rendered with one image; and while it is still on screen, you change the image to something else. In this case, just changing the image will not always trigger a repaint of the view, for that to occur you need to make a call to setNeedsDisplay.
reloadData
It has to be called when the underlying data source for the tableview is changed and you want that to be refelected in UI.In that case call this reloadData mehod
Generally, you only need to call setNeedsDisplay on custom views for which you have implemented drawRect.
My solution was to update all visible cells and keep track of indexPath of cell in my custom class "ProductTableViewCell" with reloadRowsAtIndexPaths, see below:
NSArray *arrayCells = [self.tableView visibleCells];
NSMutableArray *mArrayIndexPaths = [[NSMutableArray alloc] init];
for(ProductTableViewCell *cell in arrayCells) {
[mArrayIndexPaths addObject:cell.indexPath];
}
[self.tableView beginUpdates];
[self.tableView endUpdates];
[self.tableView reloadRowsAtIndexPaths:[mArrayIndexPaths copy] withRowAnimation:UITableViewRowAnimationAutomatic];
Here is how the class is defined:
#interface ProductTableViewCell : UITableViewCell {
NSString *reuseID;
}
#property (nonatomic, strong) NSIndexPath *indexPath;

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

UIView and memory management

A beginners question about how to be memory efficient when using an UIView which contains a couple of images (ca. 500K). I guess if I handle this in the wrong way and call this view ten or twenty times, my app will crash (as I have leaked about 5-10 MB of RAM).
I have an UIView which I create programatically like so:
myView = [[UIView alloc] initWithFrame:0,0,0,0];
To this view I add a couple of images so that it eats up 500K of memory. After I'm done with this view, I'd like to free up the memory again. So I coded:
[myView removeFromSuperview];
myView = nil;
[myView release];
Is this the way to go? I am particularly uncertain about the last release call. Is myView not already released if I remove it from my superview and set it to nil?
Also, would it be a good idea to simply autorelease myView in the first instance, i.e.
myView = [[[UIView alloc] initWithFrame:0,0,0,0] autorelease];
I'd be grateful for any suggestions and corrections.
You’re sending a release message to nil. The correct order for those statements would be:
[myView removeFromSuperview];
[myView release];
and optionally after that:
myView = nil;
For discussion on why to set to nil:
Set pointers to nil after release?
Is It Necessary to Set Pointers to nil in Objective-C After release?
What's the difference between setting an object to nil vs. sending it a release message in dealloc
The superview retains your view when you add it as a subview, and then releases it when you remove it. You still need you release your hold of it. You could use autorelease when allocating it, but since you need to hold on to a pointer to it to be able to send removeFromSuperview, the correct way is to send release when you are done with that pointer (and then set that pointer to nil).
If you set your view to nil before you call release, you will leak the view and then send a message to nil. First you must release the view:
[myView removeFromSuperview];
[myView release];
Then you can set your variable to nil to avoid sending a message to a deallocated instance.
About the autorelease, I think it's just a matter of personal preference, but I find it much easier to track memory issues when doing:
myView = [[[UIView alloc] initWithFrame:0,0,0,0] autorelease];
// add myView to wherever it belongs
.....
[myView removeFromSuperview];
myView = nil;
As others have pointed out, settting to myView to nil before you call release is incorrect and will leak memory.

UITableView leaking?

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)];

UIButton - should we release or not?

I want to add a button on a view dynamically. Here is the code.
UIButton *x=[UIButton buttonWithType:UIButtonTypeRoundedRect];
Here, I have not used "alloc" function.
The questions for this statements are as follow.
If we are using imageview for the same situation, we have to create an temp imageview add to your current view and release it. What to do for button?
How are buttons allocated and de-allocated?
If buttons are allocated? How it's memory is been managed?
Now when I use [x release]; - is it right or wrong?
No alloc/init or new so it will be autoreleased when it is no longer needed. When you add it to the UIView the count is increase and retained by the view, then also released when the view is released.
You do not need to call release in this case. Since you are using a convenience constructor, the object that is returned is an autoreleased object.
If you use an alloc / init form, you are responsible for releasing the object.
UIButton *x=[UIButton buttonWithType:UIButtonTypeRoundedRect];
using this method u cant relese the button
instead of use
UIButton *x = [[UIButton alloc]init];
and then release