In my tableView's cellForRowAtIndexPath method, I use a custom cell for the first row and a regular UITableViewCell for the other rows:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MyIdentifier = #"Cell";
if (indexPath.section == 0){
CustomTableViewCell *cell = (CustomTableViewCell *)[tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CustomTableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
cell.titleLabel.text = #"Custom cell";
if (isLightTheme){
cell.titleLabel.textColor = [UIColor blackColor];
}
else{
cell.titleLabel.textColor = [UIColor whiteColor];
}
return cell;
}
else{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier];
}
cell.textLabel.text = #"Other cells";
if (isLightTheme){
cell.textLabel.textColor = [UIColor blackColor];
}
else{
cell.textLabel.textColor = [UIColor whiteColor];
}
return cell;
}
}
I then call a method that changes isLightTheme and reloads data:
-(void)changeTheme{
isLightTheme = false;
[self.myTable reloadData];
}
... but my app crashes on this line:
cell.titleLabel.text = #"Custom cell";
with the error:
'-[UITableViewCell titleLabel]: unrecognized selector sent to instance
I don't understand what's going on.. the table loads perfectly fine (isLightTheme is first set to true) when the ViewController first loads, but when I change isLightTheme and reloadData it crashes. Could anybody help me out? Thanks.
Your reuse identifier is the same for both of your cells. The custom and the default. Use unique values for each.
Related
I believe I'm doing this correctly but it doesn't seem to be working? The text for the cell is written indicating the if statement is correct and is running, However the cell accessory is not changing.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
if (indexPath.section==0) {
if ([[tableContents objectAtIndex:indexPath.row] isEqual: #"New Time"]) {
cell.tintColor = [UIColor redColor];
cell.textLabel.text = [tableContents objectAtIndex:indexPath.row];
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
else{
cell.textLabel.text = [tableContents objectAtIndex:indexPath.row];
}
}
else{
cell.textLabel.text = [tableContents objectAtIndex:indexPath.row];
}
return cell;
}
Thanks for any help in advance!
Okay so tried slimming the code down to try and see whats going on, now this crashes when the view is loaded, totally confused as i have another project where this is working perfectly!
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"UserCells";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
// Configure the cell...
cell.textLabel.text = #"Hello";
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
Setting the cell tint color in cellForRowAtIndexPath did work:
cell.tintColor = [UIColor redColor]; // whatever you want
I have a table which initially has no data, and shows a UITableViewCell with a message saying the user has no data to show.
I have a method that gets called on viewDidLoad and reloads the table data. When this happens, the first table cell is still shown, and the remaining cells are below it with proper data. The first cell still shows the empty data message. Is there anything i'm missing here? I have my cellForRowAtIndexPath method below.
- (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath tableView:(UITableView *)tableView {
static NSString *CellIdentifier = #"TableViewCell";
static NSString *CellIdentifierEmpty = #"TableViewCellEmpty";
if ([[self.fetchedResultsController.sections objectAtIndex:indexPath.section] numberOfObjects] == 0) {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifierEmpty];
if(cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifierEmpty];
cell.backgroundColor = [UIColor whiteColor];
cell.textLabel.textColor = [UIColor blackColor];
cell.detailTextLabel.numberOfLines = 0;
cell.detailTextLabel.lineBreakMode = NSLineBreakByWordWrapping;
cell.detailTextLabel.textColor = [UIColor blackColor];
cell.tag = -1;
}
return [self setTextForEmptyCell:cell];
}
MyObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = // Set values
}
// Set cell details
return cell;
}
Found the issue. It was a threading issue while grabbing data from the server using AFNetworking. Check all the blocks where a new thread is being used!
I'm confused as to what the problem/difference is with this code. In the first working example, I'm loading the table view from a custom class. This works dandy.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"EventCell";
ISEventsCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.backgroundColor = [UIColor colorWithWhite:.2 alpha:.7];
ISSingleEvent *singleEvent = events[indexPath.row];
[cell populateWithEvents:(singleEvent)];
return cell;
}
Now I want to add a second section to the table view and everything seems to be going fine until I add the conditions for cellForRowAtIndexPath. I get the error "No visible interface for 'UITableViewCell' declares the selector 'populateWithPasses:'
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier1 = #"EventCell";
static NSString *CellIdentifier2 = #"FlareCell";
NSString *identityString = #"";
switch ([indexPath section]) {
case 0: {
identityString = CellIdentifier1;
break;
}
case 1: {
identityString = CellIdentifier2;
break;
}
default:
break;
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identityString];
if ([indexPath section] == 0) {
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue2
reuseIdentifier:CellIdentifier1];
cell.backgroundColor = [UIColor colorWithWhite:.2 alpha:.7];
ISSingleEvent *singleEvent = events[indexPath.row];
// Error here (below) "No visible interface for 'UITableViewCell' declares the selector 'populateWithEvents:'
[cell populateWithEvents:(singleEvent)];
}
} else {
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier2];
cell.backgroundColor = [UIColor colorWithWhite:.2 alpha:.7];
ISFlareEvent *singleEvent = flareEvents[indexPath.row];
// Error here (below) "No visible interface for 'UITableViewCell' declares the selector 'populateWithFlares:'"
[cell populateWithFlares:(singleEvent)];
}
}
return cell;
}
So what am I doing wrong here? When I called "populateWithEvents" with only one section, it didn't throw an error. Now I've set up two section, each with it's own tableviewcell and it's just not working. Any help would be greatly appreciated.
Thanks,
just cast your cell like this
[(ISEventsCell *)cell populateWithFlares:(singleEvent)];
You are trying to call populateWithFlares: for UITableviewCell. The metho is defined for ISEventsCell
My UITableView is currently using a custom green color for the checkmark accessory, I set this by simply using [[UITableViewCell appearance] setTintColor:[UIColor colorWithHexString:#"#669900"]];. This works just fine, except there is always one cell, that repeats(b/c of cell reuse), that stays the default blue. I have no idea why this is happening, if anyone knows what you can do to prevent this "odd man out" problem I'm having, please share. Here's my code.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
#define CHECK_NULL_STRING(str) ([str isKindOfClass:[NSNull class]] || !str)?#"":str
static NSString *CellIdentifier = #"inviteCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
cell.textLabel.highlightedTextColor = [UIColor colorWithHexString:#"#669900"];
cell.selectionStyle = UITableViewCellSelectionStyleGray;
cell.backgroundColor = [UIColor blackColor];
cell.textLabel.textColor = [UIColor whiteColor];
[[UITableViewCell appearance] setTintColor:[UIColor colorWithHexString:#"#669900"]];
if (cell == nil) {
cell = [[UITableViewCell alloc] init];
}
if (cell == nil) {cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; }
BOOL isSearching = tableView != self.tableView;
NSArray *arrayToUse = (isSearching ? searchResults : contactsObjects);
id p = arrayToUse[indexPath.row];
NSString *fName = (__bridge_transfer NSString *)(ABRecordCopyValue((__bridge ABRecordRef)(p), kABPersonSortByFirstName));
NSString *lName = (__bridge_transfer NSString *)(ABRecordCopyValue((__bridge ABRecordRef)(p), kABPersonSortByLastName));
cell.textLabel.text = [NSString stringWithFormat:#"%# %#", CHECK_NULL_STRING(fName), CHECK_NULL_STRING(lName)];
BOOL showCheckmark = [[stateArray objectAtIndex:indexPath.row] boolValue];
if (showCheckmark == YES)
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
NSLog(#"It hit showCheckmark = YES, and stateArray is %#",stateArray[indexPath.row]);
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
NSLog(#"It hit showCheckmark = NO, and stateArray is %#",stateArray[indexPath.row]);
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
{
id object = contactsObjects[indexPath.row];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryNone)
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[stateArray insertObject:[NSNumber numberWithBool:YES] atIndex:indexPath.row];
[selectedObjects addObject:object];
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
[stateArray insertObject:[NSNumber numberWithBool:NO] atIndex:indexPath.row];
[selectedObjects removeObject:object];
}
//slow-motion selection animation.
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
There are several issues with your code.
You are setting an appearance selector multiple times. These only need to be called once to set a particular attribute. You should probably do this in your AppDelegate or somewhere else that gets called on app startup.
This is the line in question:
[[UITableViewCell appearance] setTintColor:[UIColor colorWithHexString:#"#669900"]];
Once you fix this, the issue you're posting about will actually be fixed. The reason this is occurring is because the appearance selector is only used on newly initialized objects.
- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath not only dequeues a cell but also initializes one if there is nothing to dequeue. What this means is that exactly one cell is created without the tintColor you want before your appearance selector is set.
As I mentioned before, the method you are calling actually creates a cell if needed. This means that all of this:
if (cell == nil) {
cell = [[UITableViewCell alloc] init];
}
if (cell == nil) {cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; }
well never get called, so you might as well get rid of it.
Your logic is wrong when you get a new cell. You set some of the cell attributes before you check if you have a cell. Do the check for 'nil', get a new cell if necessary, then mess about with your cell.
I am trying to put a cell as a space between each cell - which will be hidden by setting alpha = 0. In my table, the space cells will be for rows that are odd.
Note that the actual cell height is 85, but the hidden cell height (ie space between cells) is 20.
The problem is that the space cell height is 85, but not 20, I don't know why. Maybe the cell is not loaded correctly.
Cell here is the UITableViewCell - the actual cell - with identifier 'Cell'.
Cell2 is the space with identifier 'Space'.
Each class above has its own UITableViewCell class and the XIB files are also assigned to each of them. The identifier is also set in the IB for each Xib.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier1 = #"Cell";
static NSString *CellIdentifier2 = #"Space";
Cell *cell = (Cell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier1];
if(!cell)
{
NSArray *ar = [[NSBundle mainBundle] loadNibNamed:#"CellView" owner:nil options:nil];
for (id obj in ar)
{
if ([obj isKindOfClass:[Cell class]])
{
cell = (Cell *)obj;
break;
}
}
}
if (indexPath.row % 2 == 1)
{
Cell2 *cell2 = (Cell2 *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
if (!cell2)
{
NSArray *ar = [[NSBundle mainBundle] loadNibNamed:#"Cell2" owner:nil options:nil];
for(id obj in ar)
{
if([obj isKindOfClass:[Cell2 class]])
{
cell2 = (Cell2 *)obj;
break;
}
}
// Method 1
cell2 = [[Cell2 alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier2];
// Method 2
//cell2 = [[Cell2 alloc] init];
// Method 3
//cell2 = (Cell2 *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
[cell2.contentView setAlpha:0];
// prevent selection and other stuff
[cell2 setUserInteractionEnabled:NO];
}
return cell2;
}
else
{
// Configure the actual cell
}
return cell;
}
* I've renamed some of your NIB/Class names for a better understanding. *
First, you should register each cells' NIB:
- (void)viewDidLoad{
[super viewDidLoad];
static NSString *CellIdentifier1 = #"ContentCell";
static NSString *CellIdentifier2 = #"SpaceCell";
UINib *nib = [UINib nibWithNibName:#"CellViewNIBName" bundle:nil];
[self.tableView registerNib:nib forCellReuseIdentifier:CellIdentifier1];
nib = [UINib nibWithNibName:#"CellSpaceNIBName" bundle:nil];
[self.tableView registerNib:nib forCellReuseIdentifier:CellIdentifier2];
self.contentView.hidden = YES;
[self loadData];
}
Because you have the NIBs registered, dequeueReusableCellWithIdentifier: will always return a cell:
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier1 = #"ContentCell";
static NSString *CellIdentifier2 = #"SpaceCell";
// Space Cell
if (indexPath.row % 2 == 1) {
CellSpace *cell = (CellSpace *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
return cell;
}
// Content cell
else {
CellView *cell = (CellView *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier1];
// Configure cell
return cell;
}
}
Last, but not least, make sure to implement the following delegate method:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Space cell's height
if (indexPath.row % 2 == 1) {
return 20.0f;
}
// Content cell's height
else {
return 80.0f;
}
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *returncell;
static NSString *cellIdentifier ;
if(indexPath.section == 0)
{
cellIdentifier = #"cell1";
}
else if (indexPath.section == 1)
{
cellIdentifier = #"cell2";
}
UITableViewCell *myCell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
MapTableViewCell *myCustomCell = (MapTableViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if(indexPath.section == 0)
{
if(myCell == nil)
{
myCell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
getLocationBtn = [UIButton buttonWithType:UIButtonTypeCustom];
getLocationBtn.frame = CGRectMake(myCell.frame.origin.x,myCell.frame.origin.y+5 , 200, 30);
[getLocationBtn setTitle:#"your button title" forState:UIControlStateNormal];
[getLocationBtn setTitleColor:[UIColor orangeColor] forState:UIControlStateNormal];
[getLocationBtn addTarget:self action:#selector(buttonAction) forControlEvents:UIControlEventTouchUpInside];
}
[myCell.contentView addSubview:getLocationBtn];
returncell = myCell;
}
else if (indexPath.section == 1)
{
if (myCustomCell == nil)
{
myCustomCell = [[MapTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
myCustomCell.nearbyLocation.text = #"demo Text";
returncell = myCustomCell;
}
return returncell;
}
//mycustom tablviewcell
import "MapTableViewCell.h"
#implementation MapTableViewCell
#synthesize nearbyLocation;
-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if(self)
{
self.backgroundColor = [UIColor groupTableViewBackgroundColor];
nearbyLocation = [[UILabel alloc]initWithFrame:CGRectMake(10, 5, 200, 30)];
[self addSubview:nearbyLocation];
}
return self;
}
#end
Best way to use number of custom cells with default cell
In addition for the answers provided, I want to emphasize on the Cell Identifier for each different custom cells must be different too.
For example custom cellA with identifier "Cell" and custom cellB with identifier "Cell2".