Question

I believe this question is my exact problem, but I was not able to fix the issue looking at the accepted answer. UISearchBar: FilterContentForSearchText not working on a UITableView (results not shown on table)

I have a UITableViewController that allows searching. It was working perfectly via the default UITableViewCellStyle, then I decided to implement my own custom layout for the cells. I did not subclass UITableViewCell, but instead added two UILabels to the cell via Interface Builder and set up Auto Layout. I assigned them unique tags so that I can reference those labels in cellForRowAtIndexPath:. It works great - everything appears as expected, until you search. The search does work and it displays the sections and rows, but the labels on the rows have no text so the cell appears completely blank.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{
    static NSString *CellIdentifier = @"List View Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }

    UILabel *leftLabel = (UILabel *)[cell viewWithTag:100];
    UILabel *rightLabel = (UILabel *)[cell viewWithTag:101];

    if (tableView == self.searchDisplayController.searchResultsTableView) {
        leftLabel.text = ...;
        rightLabel.text = ...;
    }
    else {
        leftLabel.text = ...;
        rightLabel.text = ...;
    }
    return cell;
}

I do know why the labels are blank. When you search, dequeueReusableCellWithIdentifier: returns nil so it inits a new cell with the reuse identifier, but that cell does not have a viewWithTag: and this results in left and right label becoming nil. So it obviously cannot add text to nil.

The answer provided in the link stated you should create the label in the if (!cell) statement and then call [cell.contentView addSubview:left{right}Label];. I did that, and then moved my label configuration code into that if statement as well. But when I do that, the main table's rows only has the default values of my left and right labels from Storyboard - it doesn't set the text of the labels. This is because dequeueReusableCellWithIdentifier: doesn't return nil and instead creates a new cell, so it doesn't ever set the text because that's in the if (!cell) statement.

I could not figure out how to take care of both situations: when cell is nil and when it is not. What do I need to do to fix this?

More comments: I've never used xib files before and I'd prefer to keep it that way. :) I wouldn't mind subclassing UITableViewCell if that's a solution. Of course, I would like to implement this the "proper" way - only create a cell when one is needed etc.

Was it helpful?

Solution

I think the easiest way to do this is to make your cell in a xib file if you want to use the same cell type for both the main table and the search results table. You can make a subclass if you want (you only need to put in IBOutlets to your two labels in the .h file), or do it the same way you already did using tags. In viewDidLoad of the table view controller, register the nib for both tables,

[self.searchDisplayController.searchResultsTableView registerNib:[UINib nibWithNibName:@"CommonCell" bundle:nil] forCellReuseIdentifier:@"CommonCell"];
[self.tableView registerNib:[UINib nibWithNibName:@"CommonCell" bundle:nil] forCellReuseIdentifier:@"CommonCell"];

Then in cellForRowAtIndexPath:, you only need to dequeue the cell with that same identifier, and populate the labels. There's no need to check for cell equals nil, because it never will be.

I modified one of my apps to show how you can implement cellForRowAtIndexPath. I subclassed the cell (CommonCell is the class), only adding IBOutlets to the leftLabel, and rightLabel,

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    CommonCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CommonCell" forIndexPath:indexPath];
    cell.leftLabel.text = ([tableView isEqual:self.tableView])? self.theData[indexPath.row] : self.filteredData[indexPath.row];
    cell.rightLabel.text = ([tableView isEqual:self.tableView])? self.theData[indexPath.row] : self.filteredData[indexPath.row];
    return cell;
}

OTHER TIPS

This is conceptually wrong: you are instantiate a NEW CELL from code that is not the cell from interface builder. If you want use that on interface builder you need to register the nib for your tableView, and associate it to an identifier (se the same identifier also in the cell on interface builder):

[self.searchDisplayController.searchResultsTableView registerNib:[UINib nibWithNibName:@"NameNib" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:@"Identifier"];

But the question is: why? The best thing to do is create a subclass and add your labels. It is really simple:

1) Create a new file CustomSearchCell object that extends UITableViewCell:

CustomSearchCell.h

#import <UIKit/UIKit.h>

@interface CustomSearchCell : UITableViewCell

@property (strong, nonatomic) UILabel *leftLabel;
@property (strong, nonatomic) UILabel *rightLabel;

@end

CustomSearchCell.m

#import "CustomSearchCell.h"

@implementation CustomSearchCell

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        // Initialization code
        _leftLabel = [[UILabel alloc] initWithFrame:CGRectMake(100, 10, 200, 45)];
        [_leftLabel setFont:[UIFont systemFontOfSize:20.0]];
        [_leftLabel setTextColor:[UIColor blackColor]];

        _rightLabel = [[UILabel alloc] initWithFrame:CGRectMake(100, 45, 200, 25)];
        [_rightLabel setFont:[UIFont systemFontOfSize:15.0]];
        [_rightLabel setTextColor:[UIColor grayColor]];

        [self.contentView addSubview: _leftLabel];
        [self.contentView addSubview: _rightLabel];
    }
    return self;
}

@end

2) In your view controller:

#import "CustomSearchCell.h"

and:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{
    static NSString *CellIdentifier = @"ListCellIdentifier";
    CustomSearchCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (!cell) {
        cell = [[CustomSearchCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }

    if (tableView == self.searchDisplayController.searchResultsTableView) {
        cell.leftLabel = ...;
        cell.rightLabel = ...;
    }
    else {
        cell.leftLabel = ...;
        cell.rightLabel = ...;
    }

    return cell;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top