Reputation: 1208
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,
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]
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
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