Custom UITableViewCell On Autorelease causes a crash in application - iphone

I have a custom cell for my table view which I have designed using interface builder. In its .m file I have some code like this to fetch the xib from the bundle for the custom cell.
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
NSArray *nibArray = [[NSBundle mainBundle] loadNibNamed:#"SubItemsCustomCell" owner:self options:nil];
self = [nibArray objectAtIndex:0]; }
return self;
}
Then when I use this cell in my cellForRowAtIndexPath method and pass it an autorelease message
if (!cellForSubItems) {
cellForSubItems = [[[SubItemsCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"SubItemCell"] autorelease];
}
it crashes when i scroll the tableView giving a message,
-[SubItemsCustomCell release]: message sent to deallocated instance 0xed198b0
It never crashed when I made a custom cell using code, but it does here, why is it so??
Also when I dont autorelease it, it runs absolutely fine, but obviously it will have memory leaks.
Kindly Help me out with this one. Thanks In Advance.
EDIT: I am not using ARC.

Your init method looks very wrong.
At the time it is called, an object has already been allocated. Then, you replace that object with something you load from a nib. Here you already leak the old instance, which you should release first. The new object from the nib is autoreleased (see naming conventions), so you should retain it here.
I strongly suggest removing that bogus code altogether. You don't want to manually call alloc/init, just to replace it with something from a nib there. Load from the nib directly.
So yes, your code may leak, but probably not the way you thought of.

try my bellow code for add cell in UITableView
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
SubItemsCustomCell *cell = (SubItemsCustomCell *) [tableView dequeueReusableCellWithIdentifier:nil];
if (cell == nil)
{
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"SubItemsCustomCell" owner:self options:nil];
for (id currentObject in topLevelObjects){
if ([currentObject isKindOfClass:[UITableViewCell class]]){
cell = (SubItemsCustomCell *) currentObject;
break;
}
}
///do something here
}
return cell;
}
i hope this help you...
:)

Related

Custom UITableViewCell Not Using .xib (Most Likely Because of Flaw in init Method)

I subclassed the UITableViewCell in order to customize it, but I think I'm missing something because: 1) It's not working and 2) There are a couple of things I'm confused on. Along with customizing the look of the .xib file, I also changed the backgroundView, and that part is working fine. The part that I least understand/am most confused about is the init method, so I posted that here. If it turns out that is correct, please tell me so I can post more code that may be the cause.
This is the init method, which I customized. I'm sort of confused around the "style" idea and I think I'm just returning a normal UITableViewCell with a different backgroundView. I mean, there's nothing in there that refers to the .xib or does anything but change the .backgroundView from the self:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier wait: (float) wait fadeOut: (float) fadeOut fadeIn: (float) fadeIn playFor: (float) playFor
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
CueLoadingView* lview = [[CueLoadingView alloc] initWithFrame:CGRectMake(0, 0, 320, 53)];
self.backgroundView = lview;
[self setWait:wait]; // in turn edits the lview through the backgrounView pointer
[self setFadeOut:fadeOut];
[self setFadeIn:fadeIn];
[self setPlayFor:playFor];
}
return self;
}
Other than the .xib and several setters and getters, this is the only real part of my code, that relates to retrieving a cell.
Additional Information:
1) This is my .xib, which is linked to the class.
2) This is the code that calls/creates the UITableView (the delegate/view controller):
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"CueTableCell";
CueTableCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[CueTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier wait:5.0 fadeOut:1.0 fadeIn:1.0 playFor:10.0];
[cell updateBarAt:15];
}
return cell;
}
The easiest way (available since iOS 5.0) to create a custom table view cell in a nib file is to use registerNib:forCellReuseIdentifier: in the table view controller. The big advantage is that dequeueReusableCellWithIdentifier: then automatically instantiates a cell from the nib file if necessary. You don't need the if (cell == nil) ... part anymore.
In viewDidLoad of the table view controller you add
[self.tableView registerNib:[UINib nibWithNibName:#"CueTableCell" bundle:nil] forCellReuseIdentifier:#"CueTableCell"];
and in cellForRowAtIndexPath you just do
CueTableCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CueTableCell"];
// setup cell
return cell;
Cells loaded from a nib file are instantiated using initWithCoder, you can override that in your subclass if necessary. For modifications to the UI elements, you should override awakeFromNib (don't forget to call "super").
You have to load the cell from the .xib instead:
if ( cell == nil ) {
cell = [[NSBundle mainBundle] loadNibNamed:#"CellXIBName" owner:nil options:nil][0];
}
// set the cell's properties
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"CueTableCell";
CueTableCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
NSArray *array = [[NSBundle mainBundle] loadNibNamed:#"CueTableCell XibName" owner:self options:nil];
// Grab a pointer to the first object (presumably the custom cell, as that's all the XIB should contain).
cell = [array objectAtIndex:0];
}
return cell;
}

Dealloc of custom cell loaded from NIB is not called

So I have a subclass UITableViewCell named MCProductCell, which is loaded from a NIB. The problem is that when the table is released, the dealloc method of my custom cell is not called even once.
Here is some sample code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"MCProductCellIdentifier";
MCProductCell *cell = (MCProductCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
// Boolean value needed to determine if it is a reused cell or not. If it's not reused we have
// to start the thread that loads the image. For reused cells, that thread is started at the
// end of the scrolling
BOOL recycled = YES;
if (cell == nil) {
NSLog(#"cell alloc");
recycled = NO;
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"MCProductCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
MCProduct *product = [products objectAtIndex:indexPath.row];
cell.product = product;
cell.cartViewController = self;
cell.productImage = product.cachedThumbnailImage;
if (product.cachedThumbnailImage == nil) {
cell.productImage = [ViewControllerUtils getDefaultImage];
if (!recycled)
[NSThread detachNewThreadSelector:#selector(loadImage:) toTarget:cell withObject:cell.product.imageThumbnailUrl];
}
return cell;
}
And for some reason, when I first present my UIViewController, that contains the table, the dealloc method of my custom cell is called ONCE.
The problem is that in the dealloc method I want to remove the cell as an observer, and if it isn't called, then the cell isn't removed as an observer.
Also the tableview is an outlet.
I figured out, it must be because the retain count of the cell is not going down to 0.
Which means you have another retain.
My more experienced colleague thinks its because you are using the detachNewThreadSelector, which probably retains the cell.
He suggested you would load the image by using some type of asynchrony image such as
https://github.com/nicklockwood/AsyncImageView/
Good luck.
How is the 'cell.cartViewController' property defined? If it's retaining your controller object (self), then you probably have a retain cycle in there!

Custom cell and UITableViewCell problems

Newbie here, just learning!
I'm trying to create a table view app with just three custom cells. Each cell needs to have an a label and an image on the left (so far I've only bothered with the label part). So far this guide
has been very useful. I created an array with three items and got it to load just fine, but when I tried to implement a custom cell everything broke. For this portion of code:
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CustomCell";
CustomCell *cell = (CustomCell *)
[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil){
NSArray *topLevelObjects = [[NSBundle mainBundle]
loadNibNamed:#"CustomCell"
owner:nil options:nil];
for(id currentObject in topLevelObjects)
{
if ([currentObject isKindOfClass:[UITableViewCell class]])
{
cell = (CustomCell *) currentObject;
break;
}
}
}
cell.issue.text = array objectAtIndex:[indexPath.row];
return cell;
}
I get the errors Unused variable CellIdentifier, CustomCell undeclared, Expected expression before ) token and Control reaches end of non-void function.
I don't know what would cause these and I'm kind of at a dead end as far as my knowledge of what to look for. Sorry for my newbness, and any pointing in the right direction would be appreciated.
edit:
Heyooo! Thanks, importing CustomCell fixed a ton of the problems! Now there are no visible errors before running it, but when I try and run it, I just get sent to
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [array count];
with a red arrow pointing to return [array count];
The current array code I have is:
- (void)viewDidLoad {
[super viewDidLoad];
array = [[NSMutableArray alloc] init];
[array addObject:#"Eleven"];
[array addObject:#"Ten"];
[array addObject:#"Nine"];
Wow, what a helpful and responsive community. Can't thank you enough.
All you need is import declaration of CustomCell class.
#import "CustomCell.h" // for example.
You probably just missed a step. Have you made CustomCell.m, CustomCell.m and CustomCell.xib files? If so, you will need to import the header file.
#import "CustomCell.h"

iphone how to access a custom cell outside of cellForRowAtIndexPath

i have set up a tableview with custom cells. customCell is a class.
heres the code for a more accurate view:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSManagedObject *object = (NSManagedObject *)[entityArray objectAtIndex:indexPath.row];
NSString *cellIdentifier = [NSString stringWithFormat:#"asd%d", indexPath.row];
customCell *cell = [[tableView dequeueReusableCellWithIdentifier:cellIdentifier] autorelease];
//i tried setting a tag but dunno how to call it afterwards
[cell setTag:indexPath.row];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"customCell" owner:self options:nil];
cell = [topLevelObjects objectAtIndex:0];
}
if (cell.imagen != nil) {
[[cell imageView] setImage:[cell imagen]];
} else { /* setup image... */ }
}
-(void) webImageReady:(WebImage *)downloadedImage imageView:(UIImageView *)imageView cellTag:(NSInteger *)cTag
{
// This is the part where i want to access cell.imagen, this is actually wrong...
[[[imageView.superview viewWithTag:cTag] imagen] setImagen:downloadedImage.Image];
[imageView setImage:downloadedImage.Image];
}
Ok. now i want to access (reference) the cell.imagen property from a method outside cellForRowAtIndexPath, more precisely at a selector for a download finished (delegated)
Thanks in advance!
Do it inside cellForRowAtIndexPath if the image is downloaded, and on successful download of the image do [tableview setNeedsDisplay]
You shouldn't refer to the cell outside the cell creation method, you should consider the case the cell was rendered but while getting the image was scrolled out the dealloced or even reused for another cell, one way to solve it is to have image view array or something similar.
I think you should try using a third party lib that already doing it(among other things) called Three20. It have an object call TTImageView that gets a URL and loads it in the background, it solves all of the cases along with optimized caching

Why is Instruments reporting custom UITableViewCell code as a memory leak?

I'm still trying to find my way through memory management for the iPhone SDK, and I'm not sure why Instruments is reporting a certain block of code as a memory leak. I've followed tutorials for these parts of the code, so I'm not really sure what I'm doing wrong.
The violating block of code:
DreamTableCell *cell = (DreamTableCell *)[tableView dequeueReusableCellWithIdentifier:cellID];
if ( cell == nil )
cell = [[[DreamTableCell alloc] initWithFrame:CGRectZero reuseIdentifier:cellID] autorelease];
Also, there is a custom method of DreamTableCell where the UITableViewCell's NIB file is loaded, nothing abnormal, as far as I know:
- (id)initWithFrame:(CGRect)frame reuseIdentifier:(NSString *)reuseIdentifier {
NSArray *objs = [[NSBundle mainBundle] loadNibNamed:#"DreamTableCell" owner:nil options:nil];
for ( id item in objs )
if ( [item isKindOfClass:[DreamTableCell class]] ) {
self = item;
break;
}
return self;
}
What's causing the memory leak here - what am I missing?
It's the line:
self = item;
You're setting self to a new instance variable, and since you're in init, an existing instance has been created. You need to release the brand-new self before you set it to something else:
[self release];
self = item;