markich
markich

Reputation: 356

Label in [cell viewWithTag:] is always returned as nil

I'm struggling with this basic thing for more than a day and it drives me crazy! Funny thing is, I have very similar thing on other screen and it works just fine! I have done this a thousand times, but never experienced something so odd. Maybe is this behavior in iOS 8 only?

On my very simple Prototype cell I have two labels with tags 102 and 103. But when I want to set text to them, they are always nil.

I have double checked that identifier is correct and that tag is the same as in Storyboard.

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString * identifier = @"secondReusableIdentifier";
    UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:identifier];
    if (cell == nil){
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
    }

    for (UIView *subview in [cell subviews]) {
        NSLog(@"subview: %lu", subview.tag); // prints 0
    }

    UILabel * label1 = (UILabel *)[cell viewWithTag:102]; // returns nil
    UILabel * label2 = (UILabel *)[cell viewWithTag:103]; // returns nil
    if (self.items.count) {
        MyObject *obj = [self.items objectAtIndex:indexPath.row];
        label1.text = obj.someProperty;
        fuelPrice2.text = obj.someOtherProperty;
        }
    }
    return cell;

Any suggestions would be appreciated.

Upvotes: 2

Views: 3088

Answers (3)

Rashad
Rashad

Reputation: 11197

Replacing this:

NSString * identifier = @"secondReusableIdentifier";
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil){
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}

BY

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"secondReusableIdentifier" forIndexPath:indexPath];

for creating a cell will solve your problem because, it always returns a cell. It either re uses existing cells or creates a new one and returns if there are no cells.

The most important difference is that the forIndexPath: version crashes if you didn't register a class or nib for the identifier. The older (non-forIndexPath:) version returns nil in that case.

You must register a class or nib for using this. But if you create your table view and your cell prototypes in a storyboard, the storyboard loader takes care of registering the cell prototypes that you defined in the storyboard.

Hope this helps.. :)

Upvotes: 1

Onik IV
Onik IV

Reputation: 5047

In your code you are creating a new cell, that it's not the same than you have in Storyboard.

Change this: This is the old way, or the way you use when the cell is by code or nib, and you don't use storyboard. This code means.

      NSString * identifier = @"secondReusableIdentifier";
// If I have available a cell with this identifier: secondReusableIdentifier, let's go to use it.
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil){
 // If not, we create a new cell with this identifier. This methods is previous to storyboard, and this methods create a new cell, but does´t look in Storyboard if this identifier exist, or something like that.

    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}

To this, in other hand when Apple launched storyboard the framework grow with this methods, that work in this way: If there is a cell free use it, if not it look in Storyboard for a cell with this identifier and create a new cell with this info. (You can use this methods also by code and with nib file, but you must register the class before...).

 // Be sure than: "secondReusableIdentifier", it's its identifier in storyboard
  UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"secondReusableIdentifier" forIndexPath:indexPath];

Upvotes: 2

Luca D'Alberti
Luca D'Alberti

Reputation: 4849

If

for (UIView *subview in [cell subviews]) {
    NSLog(@"subview: %lu", subview.tag); // prints 0
}

prints 0, why do you do this??

UILabel * label1 = (UILabel *)[cell viewWithTag:102];
UILabel * label2 = (UILabel *)[cell viewWithTag:103];

So, if you created a custom cell with IB, you have to create a custom class and use it instead of a simple UITableViewCell

Upvotes: 0

Related Questions