Chocksmith
Chocksmith

Reputation: 1208

Unable to retrieve contentView of a UITableViewCell

I definitively need help here...

I am creating a custom UITableViewCell programmatically adding subviews to a Cell’s content view.

I followed the example of the tutorial: https://developer.apple.com/library/ios/documentation/userexperience/Conceptual/TableView_iPhone/TableViewCells/TableViewCells.html

First it creates the reusable cell or get the content view if it already exists. Then it set the picture.

#import "NSString+MD5.h"
#import "UIImageView+Network.h"

(....)

#define PHOTO_TAG 1
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *cellIdentifier = @"CustomCell";
    PELOTFriendTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    UIImageView *photo;
    if (cell == nil) {
        NSLog(@"Creating cell");
        cell = [[PELOTFriendTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
        cell.selectionStyle = UITableViewCellSelectionStyleNone;

        photo = [[UIImageView alloc] initWithFrame:CGRectMake(42, 17, 55, 55)];
        photo.tag = PHOTO_TAG;
        photo.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight;
        [cell.contentView addSubview:photo];

    } else {
        NSLog(@"Reusing cell");
        photo = (UIImageView *)[cell.contentView viewWithTag:PHOTO_TAG];
        NSLog(@"%@",photo);
    }

(....)

    if (friend.pictureUrl==nil) {
        NSLog(@"Setting default photo");
        [photo setImage:[UIImage imageNamed:@"user-picture.png"]];
    } else {
        NSLog(@"Setting photo from URL");
        [photo loadImageFromURL:[[NSURL alloc]initWithString:friend.pictureUrl] placeholderImage:[UIImage imageNamed:@"user-picture.png"] cachingKey: [friend.pictureUrl MD5Hash]];
    }

The NSLog shows me that

photo = (UIImageView *)[cell.contentView viewWithTag:PHOTO_TAG];

sometimes returns UITableViewCellContentView* instead of UIImageView* and I get an "unrecognized selector" error.

2014-08-15 11:41:27.747 MyApp[79972:60b] <UIImageView: 0xc722840; frame = (60 17; 55 90); opaque = NO; autoresize = LM+H; userInteractionEnabled = NO; tag = 1; layer = <CALayer: 0xc7228c0>>

2014-08-15 11:41:27.750 MyApp[79972:60b] <UITableViewCellContentView: 0xc840c90; frame = (0 0; 338 79.5); tag = 1; gestureRecognizers = <NSArray: 0xc8409d0>; layer = <CALayer: 0xc840b60>>

The first one was the image initialized with [photo setImage] and the second one was the image initialized with [photo loadImageFromURL].

It is driving me crazy. Any thoughts?

Tks,

EDIT 1

The first time it renders the table, it works. The problem happens when I call [tableview reloadData] and it calls [cell.contentView viewWithTag:PHOTO_TAG]

EDIT 2

The reproducible code is:

PELOTReproduceBugViewController.h

#import <UIKit/UIKit.h>

@interface PELOTReproduceBugViewController : UIViewController <UITableViewDelegate>

@property (nonatomic,retain) IBOutlet UITableView *friendsTableView;
@property (nonatomic,retain) IBOutlet UIButton *reloadButton;

-(IBAction)reload:(id)sender;

@end

PELOTReproduceBugViewController.m

#import "PELOTReproduceBugViewController.h"

@implementation PELOTReproduceBugViewController

@synthesize friendsTableView;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

-(IBAction)reload:(id)sender {
    NSLog(@"reload!");
    [friendsTableView reloadData];
}


- (void)viewDidLoad
{
    NSLog(@"viewDidLoad!");
    [super viewDidLoad];

    friendsTableView.delegate = self;

    friendsTableView.backgroundColor = [UIColor clearColor];
    friendsTableView.opaque = NO;
    friendsTableView.backgroundView = nil;

}


- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void)popViewToGetBack:(id)sender {
    [self.navigationController popViewControllerAnimated:YES];
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    // Return the number of sections.
    NSLog(@"** numberOfSectionsInTableView");
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    NSLog(@"** numberOfRowsInSection");
    return 3;
}

#define PHOTO_TAG 1
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    int row = (int) [indexPath row];
    static NSString *cellIdentifier = @"CustomCell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];

    NSLog(@"** 1[%d]",row);

    UIImageView *photo=nil;
    if (cell == nil) {
        NSLog(@"Creating cell");
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
        cell.selectionStyle = UITableViewCellSelectionStyleNone;
        cell.contentView.tag = indexPath.row;

        photo = [[UIImageView alloc] initWithFrame:CGRectMake(42, 17, 55, 55)];
        photo.tag = PHOTO_TAG;
        photo.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight;
        [cell.contentView addSubview:photo];

        NSLog(@"** 2a[%d]: %@",row,photo);
    } else {
        photo = (UIImageView *)[cell.contentView viewWithTag:PHOTO_TAG];
        NSLog(@"** 2b[%d]: %@",row,photo);
    }

    // Configure the cell...

    NSLog(@"** 3 %d",row);
    [photo setImage:[UIImage imageNamed:@"user-picture.png"]];

    NSLog(@"** 4");
    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 80;
}




/*
 #pragma mark - Navigation

 // In a storyboard-based application, you will often want to do a little preparation before navigation
 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
 {
 // Get the new view controller using [segue destinationViewController].
 // Pass the selected object to the new view controller.
 }
 */

@end

The output is:

2014-08-16 17:46:43.432 BugApp[83096:60b] viewDidLoad!
2014-08-16 17:46:43.447 BugApp[83096:60b] ** numberOfSectionsInTableView
2014-08-16 17:46:43.450 BugApp[83096:60b] ** numberOfRowsInSection
2014-08-16 17:46:43.452 BugApp[83096:60b] ** 1[0]
2014-08-16 17:46:43.453 BugApp[83096:60b] Creating cell
2014-08-16 17:46:43.455 BugApp[83096:60b] ** 2a[0]: <UIImageView: 0xc8b23f0; frame = (42 17; 55 55); autoresize = LM+H; userInteractionEnabled = NO; tag = 1; layer = <CALayer: 0xc8b2470>>
2014-08-16 17:46:43.456 BugApp[83096:60b] ** 3 0
2014-08-16 17:46:43.459 BugApp[83096:60b] ** 4
2014-08-16 17:46:43.460 BugApp[83096:60b] ** 1[1]
2014-08-16 17:46:43.461 BugApp[83096:60b] Creating cell
2014-08-16 17:46:43.463 BugApp[83096:60b] ** 2a[1]: <UIImageView: 0xc8b5150; frame = (42 17; 55 55); autoresize = LM+H; userInteractionEnabled = NO; tag = 1; layer = <CALayer: 0xc8b51d0>>
2014-08-16 17:46:43.464 BugApp[83096:60b] ** 3 1
2014-08-16 17:46:43.465 BugApp[83096:60b] ** 4
2014-08-16 17:46:43.467 BugApp[83096:60b] ** 1[2]
2014-08-16 17:46:43.468 BugApp[83096:60b] Creating cell
2014-08-16 17:46:43.470 BugApp[83096:60b] ** 2a[2]: <UIImageView: 0xc7ef9a0; frame = (42 17; 55 55); autoresize = LM+H; userInteractionEnabled = NO; tag = 1; layer = <CALayer: 0xc7eb7a0>>
2014-08-16 17:46:43.471 BugApp[83096:60b] ** 3 2
2014-08-16 17:46:43.472 BugApp[83096:60b] ** 4

2014-08-16 17:46:48.658 BugApp[83096:60b] reload!
2014-08-16 17:46:48.658 BugApp[83096:60b] ** numberOfSectionsInTableView
2014-08-16 17:46:48.659 BugApp[83096:60b] ** numberOfRowsInSection
2014-08-16 17:46:48.660 BugApp[83096:60b] ** 1[0]
2014-08-16 17:46:48.661 BugApp[83096:60b] ** 2b[0]: <UIImageView: 0xc8b23f0; frame = (60 17; 55 90); opaque = NO; autoresize = LM+H; userInteractionEnabled = NO; tag = 1; layer = <CALayer: 0xc8b2470>>
2014-08-16 17:46:48.661 BugApp[83096:60b] ** 3 0
2014-08-16 17:46:48.661 BugApp[83096:60b] ** 4
2014-08-16 17:46:48.662 BugApp[83096:60b] ** 1[1]
2014-08-16 17:46:48.662 BugApp[83096:60b] ** 2b[1]: <UITableViewCellContentView: 0xc8b4df0; frame = (0 0; 338 79.5); tag = 1; gestureRecognizers = <NSArray: 0xc8b5100>; layer = <CALayer: 0xc8b4f60>>
2014-08-16 17:46:48.663 BugApp[83096:60b] ** 3 1
2014-08-16 17:46:48.663 BugApp[83096:60b] -[UITableViewCellContentView setImage:]: unrecognized selector sent to instance 0xc8b4df0
2014-08-16 17:46:48.678 BugApp[83096:60b] WARNING: GoogleAnalytics 3.07 void GAIUncaughtExceptionHandler(NSException *) (GAIUncaughtExceptionHandler.m:49): Uncaught exception: -[UITableViewCellContentView setImage:]: unrecognized selector sent to instance 0xc8b4df0
2014-08-16 17:46:53.684 BugApp[83096:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UITableViewCellContentView setImage:]: unrecognized selector sent to instance 0xc8b4df0'
*** First throw call stack:
(
    0   CoreFoundation                      0x021a11e4 __exceptionPreprocess + 180
    1   libobjc.A.dylib                     0x01f208e5 objc_exception_throw + 44
    2   CoreFoundation                      0x0223e243 -[NSObject(NSObject) doesNotRecognizeSelector:] + 275
    3   CoreFoundation                      0x0219150b ___forwarding___ + 1019
    4   CoreFoundation                      0x021910ee _CF_forwarding_prep_0 + 14
    5   BugApp                         0x0003387b -[PELOTReproduceBugViewController tableView:cellForRowAtIndexPath:] + 1083
    6   UIKit                               0x0057e11f -[UITableView _createPreparedCellForGlobalRow:withIndexPath:] + 412
    7   UIKit                               0x0057e1f3 -[UITableView _createPreparedCellForGlobalRow:] + 69

Note that the first time

photo = (UIImageView *)[cell.contentView viewWithTag:PHOTO_TAG];

is called, it works. The second, it doesn't.

To reproduce you must call [table reloadData].

Upvotes: 1

Views: 515

Answers (1)

Colin
Colin

Reputation: 3752

The documentation for viewWithTag includes this sentence: "This method searches the current view and all of its subviews for the specified view."

When you do this: cell.contentView.tag = indexPath.row;

When indexPath.row == 1, then the cell.contentView.tag is 1, and it'll be found instead of the image, whose tag is also 1. I think it'll only happen for row 1.

Upvotes: 1

Related Questions