Reputation: 375
I'm absolutely stumped on how to fix this issue. So I have a UITableView and in the delegate method cellForRowAtIndex: I'm adding several subviews to each cell if the cell is nil (the initial building of the table view). Everything works well and the table view is built, however, when I scroll down a little in the application, the app all of a sudden crashes with SIGBART and gives me the error * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[NSIndexPath setImage:]: unrecognized selector sent to class 0x3c361e68'** It's weird because I'm not even calling a setImage method anywhere in my code. Here is the code for the delegate method.
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
UIImageView* imageView;
UILabel* ttitle;
UILabel* ttitle2;
UILabel* ttitle3;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
// Configure cell:
// *** This section should configure the cell to a state independent of
// whatever row or section the cell is in, since it is only executed
// once when the cell is first created.
imageView=[[UIImageView alloc]initWithFrame:CGRectMake(10.0, 11.0, 50.0, 50.0)];
[imageView setContentMode:UIViewContentModeScaleAspectFill];
imageView.layer.masksToBounds=YES;
imageView.layer.cornerRadius=5.0;
[cell.contentView addSubview:imageView];
ttitle = [[[UILabel alloc] initWithFrame:CGRectMake(70.0, 7.0, 200, 20)] autorelease];
ttitle.textColor= [UIColor blackColor];
ttitle.numberOfLines=1;
ttitle.backgroundColor=[UIColor clearColor];
ttitle.font=[UIFont fontWithName:@"Arial Bold" size:15.0];
[cell.contentView addSubview:ttitle];
if (indexPath.row==0) {
CGSize size=[[[data objectAtIndex:indexPath.row] valueForKey:@"content"] sizeWithFont:[UIFont systemFontOfSize:14.0f] constrainedToSize:CGSizeMake(265.0f, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
ttitle2 = [[[UILabel alloc] initWithFrame:CGRectMake(70.0, 27.5, 200, size.height)] autorelease];
ttitle2.textColor= [UIColor darkGrayColor];
ttitle2.backgroundColor=[UIColor clearColor];
ttitle2.numberOfLines=0;
ttitle2.textAlignment = NSTextAlignmentLeft;
ttitle2.lineBreakMode=NSLineBreakByWordWrapping;
ttitle2.font=[UIFont fontWithName:@"Arial" size:14.0];
[cell.contentView addSubview:ttitle2];
ttitle3 = [[[UILabel alloc] initWithFrame:CGRectMake(70.0, ttitle2.frame.origin.y+ttitle2.frame.size.height-8.0, 210, 40)] autorelease];
ttitle3.textColor= [UIColor darkGrayColor];
ttitle3.backgroundColor=[UIColor clearColor];
ttitle3.numberOfLines=1;
ttitle3.textAlignment = NSTextAlignmentLeft;
ttitle3.lineBreakMode=NSLineBreakByWordWrapping;
ttitle3.font=[UIFont fontWithName:@"Arial" size:11.0];
[cell.contentView addSubview:ttitle3];
}
else{
CGSize size=[[[data objectAtIndex:indexPath.row] valueForKey:@"content"] sizeWithFont:[UIFont systemFontOfSize:14.0f] constrainedToSize:CGSizeMake(265.0f, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
ttitle2 = [[[UILabel alloc] initWithFrame:CGRectMake(70.0, 27.0, 200, size.height)] autorelease];
ttitle2.textColor= [UIColor darkGrayColor];
ttitle2.backgroundColor=[UIColor clearColor];
ttitle2.numberOfLines=0;
ttitle2.textAlignment = NSTextAlignmentLeft;
ttitle2.lineBreakMode=NSLineBreakByWordWrapping;
ttitle2.font=[UIFont fontWithName:@"Arial" size:14.0];
[cell.contentView addSubview:ttitle2];
ttitle3 = [[[UILabel alloc] initWithFrame:CGRectMake(70.0, ttitle2.frame.origin.y+ttitle2.frame.size.height-9.0, 210, 40)] autorelease];
ttitle3.textColor= [UIColor darkGrayColor];
ttitle3.backgroundColor=[UIColor clearColor];
ttitle3.numberOfLines=1;
ttitle3.textAlignment = NSTextAlignmentLeft;
ttitle3.lineBreakMode=NSLineBreakByWordWrapping;
ttitle3.font=[UIFont fontWithName:@"Arial" size:11.0];
[cell.contentView addSubview:ttitle3];
}
}
// Customize cell:
// *** This section should customize the cell depending on what row or section
// is passed in indexPath, since this is executed every time this delegate method
// is called.
imageView.image=[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[[data objectAtIndex:indexPath.row] valueForKey:@"thumbnail"]]]];
[ttitle setText:[[data objectAtIndex:indexPath.row] valueForKey:@"name"]];
[ttitle2 setText:[[data objectAtIndex:indexPath.row] valueForKey:@"content"]];
NSString* first=[[[data objectAtIndex:indexPath.row] valueForKey:@"hashtag"] stringByAppendingString:@" "];
NSString* second =[first stringByAppendingString:[[data objectAtIndex:indexPath.row] valueForKey:@"place"]];
NSString* third=[second stringByAppendingString:@" "];
NSString* fourth=[third stringByAppendingString:@"¤ "];
NSString* conversion=[[[data objectAtIndex:indexPath.row] valueForKey:@"counter"] stringValue];
NSString* fifth=[fourth stringByAppendingString:conversion];
[ttitle3 setText:fifth];
return cell;
}
Appreciate the help guys!
*UPDATED CODE
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
UIImageView* imageView;
UILabel* ttitle;
UILabel* ttitle2;
UILabel* ttitle3;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
// Configure cell:
// *** This section should configure the cell to a state independent of
// whatever row or section the cell is in, since it is only executed
// once when the cell is first created.
imageView=[[UIImageView alloc]initWithFrame:CGRectMake(10.0, 11.0, 50.0, 50.0)];
[imageView setContentMode:UIViewContentModeScaleAspectFill];
imageView.layer.masksToBounds=YES;
imageView.layer.cornerRadius=5.0;
imageView.tag=1;
[cell.contentView addSubview:imageView];
ttitle = [[[UILabel alloc] initWithFrame:CGRectMake(70.0, 7.0, 200, 20)] autorelease];
ttitle.textColor= [UIColor blackColor];
ttitle.numberOfLines=1;
ttitle.tag=69;
ttitle.backgroundColor=[UIColor clearColor];
ttitle.font=[UIFont fontWithName:@"Arial Bold" size:15.0];
[cell.contentView addSubview:ttitle];
if (indexPath.row==0) {
CGSize size=[[[data objectAtIndex:indexPath.row] valueForKey:@"content"] sizeWithFont:[UIFont systemFontOfSize:14.0f] constrainedToSize:CGSizeMake(265.0f, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
ttitle2 = [[[UILabel alloc] initWithFrame:CGRectMake(70.0, 27.5, 200, size.height)] autorelease];
ttitle2.textColor= [UIColor darkGrayColor];
ttitle2.backgroundColor=[UIColor clearColor];
ttitle2.numberOfLines=0;
ttitle2.tag=70;
ttitle2.textAlignment = NSTextAlignmentLeft;
ttitle2.lineBreakMode=NSLineBreakByWordWrapping;
ttitle2.font=[UIFont fontWithName:@"Arial" size:14.0];
[cell.contentView addSubview:ttitle2];
ttitle3 = [[[UILabel alloc] initWithFrame:CGRectMake(70.0, ttitle2.frame.origin.y+ttitle2.frame.size.height-8.0, 210, 40)] autorelease];
ttitle3.textColor= [UIColor darkGrayColor];
ttitle3.backgroundColor=[UIColor clearColor];
ttitle3.numberOfLines=1;
ttitle3.tag=71;
ttitle3.textAlignment = NSTextAlignmentLeft;
ttitle3.lineBreakMode=NSLineBreakByWordWrapping;
ttitle3.font=[UIFont fontWithName:@"Arial" size:11.0];
[cell.contentView addSubview:ttitle3];
}
else{
CGSize size=[[[data objectAtIndex:indexPath.row] valueForKey:@"content"] sizeWithFont:[UIFont systemFontOfSize:14.0f] constrainedToSize:CGSizeMake(265.0f, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
ttitle2 = [[[UILabel alloc] initWithFrame:CGRectMake(70.0, 27.0, 200, size.height)] autorelease];
ttitle2.textColor= [UIColor darkGrayColor];
ttitle2.backgroundColor=[UIColor clearColor];
ttitle2.numberOfLines=0;
ttitle2.tag=70;
ttitle2.textAlignment = NSTextAlignmentLeft;
ttitle2.lineBreakMode=NSLineBreakByWordWrapping;
ttitle2.font=[UIFont fontWithName:@"Arial" size:14.0];
[cell.contentView addSubview:ttitle2];
ttitle3 = [[[UILabel alloc] initWithFrame:CGRectMake(70.0, ttitle2.frame.origin.y+ttitle2.frame.size.height-9.0, 210, 40)] autorelease];
ttitle3.textColor= [UIColor darkGrayColor];
ttitle3.backgroundColor=[UIColor clearColor];
ttitle3.numberOfLines=1;
ttitle3.tag=71;
ttitle3.textAlignment = NSTextAlignmentLeft;
ttitle3.lineBreakMode=NSLineBreakByWordWrapping;
ttitle3.font=[UIFont fontWithName:@"Arial" size:11.0];
[cell.contentView addSubview:ttitle3];
}
imageView.image=[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[[data objectAtIndex:indexPath.row] valueForKey:@"thumbnail"]]]];
[ttitle setText:[[data objectAtIndex:indexPath.row] valueForKey:@"name"]];
[ttitle2 setText:[[data objectAtIndex:indexPath.row] valueForKey:@"content"]];
NSString* first=[[[data objectAtIndex:indexPath.row] valueForKey:@"hashtag"] stringByAppendingString:@" "];
NSString* second =[first stringByAppendingString:[[data objectAtIndex:indexPath.row] valueForKey:@"place"]];
NSString* third=[second stringByAppendingString:@" "];
NSString* fourth=[third stringByAppendingString:@"¤ "];
NSString* conversion=[[[data objectAtIndex:indexPath.row] valueForKey:@"counter"] stringValue];
NSString* fifth=[fourth stringByAppendingString:conversion];
[ttitle3 setText:fifth];
}
else {
imageView =[cell viewWithTag:1];
ttitle=[cell viewWithTag:69];
ttitle2=[cell viewWithTag:70];
ttitle3=[cell viewWithTag:71];
}
//STUFFOUTSIDE
// Customize cell:
// *** This section should customize the cell depending on what row or section
// is passed in indexPath, since this is executed every time this delegate method
// is called.
return cell;
}
Upvotes: 1
Views: 977
Reputation: 25740
The problem is that your local variables are not being initialized when the cell is re-used. Here's the current flow for imageView:
UIImageView* imageView;
if (cell == nil)
{
// Create imageView
imageView=...
}
// If cell is being reused (ie cell is not nil) then imageView is nil at this point.
imageView.image=...
When you are reusing a table view cell, tableView:dequeueReusableCellWithIdentifier:
returns an actual cell instead of nil
and the initialization of imageView
is skipped.
You need to "find" the imageView that is in the reused cell in order to make changes to it.
Therefore, I suggest that you modify your logic like this:
UIImageView* imageView;
if (cell == nil)
{
// Create imageView
imageView=...
}
else
{
imageView = // get a reference to the imageView
}
imageView.image=...
So now, of course, the question is "how?".
A very common way is to set the tag
of the view when you create it so that you can easily retrieve it at a later time. You would use this technique like this:
// Use a unique tag number for each subview.
#define MY_IMAGEVIEW_TAG 1000
UIImageView* imageView;
if (cell == nil)
{
// Create imageView
imageView=... // Same as before
imageView.tag = MY_IMAGEVIEW_TAG;
}
else
{
// This is a cell that is being re-used and was previously created.
// Retrieve a reference to the existing image view that is already in the cell
imageView = [cell viewWithTag:MY_IMAGEVIEW_TAG];
}
// Now imageView is "safe" to use whether it is a new cell or one that is reused!
imageView.image=...
NOTE: If you are doing a lot of this, creating a UITableViewCell
subclass that has properties for each of these subviews would make the use of tags and viewWithTag unnecessary, as well as make your code easier to read.
Upvotes: 2
Reputation: 8337
@Inafziger has already posted the correct answer to this question, I just want to explain a little bit more in detail why you're seeing this "weird" crash.
I wouldn't recommend the excessive usage of tags, though. It might be a better idea to create a subclass of UITableViewCell
.
You're not initializing your imageView
and ttitle
variables:
UIImageView *imageView; // imageView can point to anything now!
UILabel* ttitle;
Usually, you'd initialize local variables to nil
or 0
(whatever makes sense) when you declare them to avoid such dangling pointers.
Because you're reusing your table view cells cell
won't always be nil
and your if-clause won't be executed:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) { // Won't be executed if the cell could be dequeued!
...
imageView = ...;
}
Hence, if cell
can be dequeued, your imageView
and ttitle
variables have still not been assigned to anything when you use them!
You're then setting the attributes of the views:
imageView.image=[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[[data objectAtIndex:indexPath.row] valueForKey:@"thumbnail"]]]];
[ttitle setText:[[data objectAtIndex:indexPath.row] valueForKey:@"name"]];
[ttitle2 setText:[[data objectAtIndex:indexPath.row] valueForKey:@"content"]]
imageView.image = ...;
is the same as calling [imageView setImage:...];
. You can read more about that here: http://www.cocoacast.com/cocoacast/?q=node/103
And that's when all comes together: imageView
isn't initialized and you're calling -setImage:
on it. Boom, crash!
In your case imageView
points to the NSIndexPath
class. This could be anything, though.
Because of that you're effectively calling -setImage:
on the NSIndexPath
class (equivalent to: +[NSIndexPath setImage:]
) and the app crashes with the +[NSIndexPath setImage:]: unrecognized selector sent to class 0x3c361e68
error message.
Upvotes: 1