user2278764
user2278764

Reputation: 55

iOS Table View - Set tag on cell or label?

I'm a newbie to iOS development. Currently learning by following tutorials from iOS Apprentice by Matthijs Hollemans. I'm using Xcode 6 and Objective-C to make the tutorial apps.

In the book's second tutorial, he teaches his readers how to build a to-do-list app with table views, navigation controllers, etc.

In the beginning: A custom Label with the text "Label" is placed in the prototype cell of the table. On running the app at this point, "Label" shows up in the app, as expected.

To display custom text in the table view, he asks the readers to set the 'Tag' identifier for the Label and then display custom text using the 'Tag' as shown in the code below. This leads to abnormal behaviour.

What this does is that it displays "Label" on launching the app. However, on scrolling the text off the screen and then back on the screen, the custom text shows up.

To resolve this, instead of setting the 'Tag' identifier on the Label, I set it on the Table View Cell, in spite of the Author of the book specifically warning against doing this. I also had to remove the default text "Label" from the Label in the table view so that the custom text and "Label" don't overlap.

This fixed the problem, but now I'm confused as to what is the correct protocol to follow for setting the 'Tag' identifier when it comes to using table views. Should the 'Tag' be set on Table View Cell or the Label? If it should be set on the Label then what could be the reason for me to run into this problem?

Here's the code for the main ViewController.m

#import "ViewController.h"
#import "ChecklistItem.h"

@interface ViewController ()

@end

@implementation ViewController

{
    NSMutableArray * _items;
}

- (void)viewDidLoad {

    [super viewDidLoad];

    _items = [[NSMutableArray alloc] initWithCapacity:20];

    ChecklistItem * item;

    item = [[ChecklistItem alloc]init];
    item.text = @"Walk the dog";
    item.checked = NO;
    [_items addObject:item];

    item = [[ChecklistItem alloc]init];
    item.text = @"Brush teeth";
    item.checked = NO;
    [_items addObject:item];

    item = [[ChecklistItem alloc]init];
    item.text = @"Prepare breakfast";
    item.checked = NO;
    [_items addObject:item];

    item = [[ChecklistItem alloc]init];
    item.text = @"Soccer practice";
    item.checked = NO;
    [_items addObject:item];

    item = [[ChecklistItem alloc]init];
    item.text = @"Eat ice cream";
    item.checked = NO;
    [_items addObject:item];

}

- (void)didReceiveMemoryWarning {

    [super didReceiveMemoryWarning];

}

//data source method no.1 to get the number of rows in section for the table view
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    return [_items count];

}

- (void)configureCheckmarkForCell:(UITableViewCell *)cell withChecklistItem:(ChecklistItem *) item {

    //if the item is checked, display checkmark
    if (item.checked) {

        cell.accessoryType = UITableViewCellAccessoryCheckmark;

    } else {

        cell.accessoryType = UITableViewCellAccessoryNone;

    }

}


- (void)configureTextForCell:(UITableViewCell *)cell withChecklistItem:(ChecklistItem *) item {

    UILabel * label = (UILabel *)[cell viewWithTag:1000];
    label.text = item.text;

}


//data source mathod no.2 to get the cell to display the row in the given index path
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"ChecklistItem"];

    ChecklistItem * item = _items[indexPath.row];

    [self configureTextForCell:cell withChecklistItem:item];
    [self configureCheckmarkForCell:cell withChecklistItem:item];

    return cell;

}


//delegate method to handle taps on rows
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    UITableViewCell * cell = [tableView cellForRowAtIndexPath:indexPath];

    ChecklistItem * item = _items[indexPath.row];

    [item toggleChecked];

    [self configureCheckmarkForCell:cell withChecklistItem:item];

    [tableView deselectRowAtIndexPath:indexPath animated:YES];

}

@end

Upvotes: 1

Views: 3810

Answers (2)

Abizern
Abizern

Reputation: 150605

I'm not familiar with the tutorial, but using tags to identify labels within cells this way is not a good idea.

The cell should know about it's own label. It's far better to just have a method on the cell that you can pass the text to, and then let the cell take care of displaying the text in the cell.

By using the tag in this way, you are expecting to know too much about the internal implementation of the cell, and this is brittle and is likely to break.

So my answer is to set the tag on neither of them, and to use a proper configuration method of the cell itself.

Edited to add

You can download a simple version of a project for configuring a cell, without using tags here https://bitbucket.org/abizern/so-27713743/get/543739690dc4.zip

Upvotes: 3

timgcarlson
timgcarlson

Reputation: 3146

An alternative way to solve this is to not deal with a view tag at all, but create a subclass of UITableViewCell and design your layout with this subclass. When you dequeue the cell in tableView: cellForRowAtIndexPath: or get the cell in tableView:didSelectRowAtIndexPath, use your subclass for the cell.

For example, create a subclass of UITableViewCell and give it a label as a property. If you're using xib's or storyboard, attach this label as an outlet. Then you can access that label directly as you would any other property.

Upvotes: 2

Related Questions