theDuncs
theDuncs

Reputation: 4843

Nested UITableView not returning any cells

I have a UITableView which has another UITableView nested inside one its cells (I know this is bad practise, don't worry!).

The problem is that when I call dequeueReusableCellWithIdentifier: I am getting nil back. HOWEVER this works just fine when the UITableView is not nested inside another one.

Is there a way to NOT reuse a UITableViewCell, but instead directly instatiate it every time?

I've tried using this:

ContactFieldCell *cell = [[ContactFieldCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:thisCellIdentifier];

which doesn't return nil, but then nothing appears in my UITableView!

Here's the code for the "parent" UITableView:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"ContactCardCell";
    ContactCardCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    NSArray *objects = [[sections objectAtIndex:indexPath.section] objectForKey:@"objects"];
    CDCard *card = [objects objectAtIndex:indexPath.row];

    cell.delegate = self;

    cell.fieldsTableView = [[CardTableViewController alloc] initWithCard:card];
    [cell.fieldsTableView.view setFrame:CGRectMake(17, 12, 256, 163)];
    [cell.contentView addSubview:cell.fieldsTableView.view];

    return cell;
}

and here's the code for the "child" UITableView:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *thisCellIdentifier = @"ContactFieldCell";

    ContactFieldCell *cell = [self.tableView dequeueReusableCellWithIdentifier:thisCellIdentifier];

    cell.delegate = self;
    cell.field = [self.card.sortedFields objectAtIndex:indexPath.row];

    return cell;
}

ContactFieldCell is a prototype cell within the storyboard. It has the following code:

@interface ContactFieldCell : UITableViewCell

@property (nonatomic, weak) id<ContactFieldCellDelegate> delegate;
@property (nonatomic, strong) CDField *field;

@property (nonatomic, strong) IBOutlet UILabel *displayNameLabel;

@end

Upvotes: 2

Views: 667

Answers (3)

Schrodingrrr
Schrodingrrr

Reputation: 4271

UITableViews are a very powerful element and can be used to build great apps.

The only thing to keep in mind is, the basics must be clear. Now from your code, I cannot make out whether you have assigned the delegates and dataSources properly, but I'll still mention it in case someone else needs it.

You have a subclassed UITableViewCell which in turn contains a UITableView. The UIViewController must be the delegate and dataSource for the outer UITableView. Make sure you have set it in both the .h and .m file.

Next, your custom cell must also be the delegate and dataSource, but for the inner UITablewView. I suppose here, you have created the inner UITableView in the init method of the UITableViewCell. Set the delegate and dataSource there itself. Then you set other runtime properties in the drawRect method (if needed) and call it's reloadData.

The UIViewController must override the delegate and dataSource methods for the outer table and the cell must override the methods for the inner table.

Also, make sure, the time the cells are plotted, your data is not nil or null.

And a very important fact, that people miss is the following code:

static NSString *CellIdentifier = @"Cell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil) {

        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];

    }

Just dequeueing the cell is not enough. The first time a cell is dequeued, it is nil because it has not been created yet. Hence the if condition. Once it is allocated and initialized and added to the table, the dequeue code works thereafter.

NOTE : After looking more closely to your code (sorry for not looking the first time), I noticed you have allocated a UITableViewController to your cell. How do you think the cell is going to display a controller? Use a UITableView instead. Try to follow the pattern I have mentioned in paragraph 3. Use a table in the custom cell as a private member (or property, your wish), allocate it in init. Assign the data to the cell from your view controller. Then use this data to set the inner table view cell's properties in it's drawRect. It should work fine.

Upvotes: 0

ansible
ansible

Reputation: 3579

Yes - @vikingosegundo is correct, but to expand his answer, you need to also register your cell first. dequeueReusableCellWithIdentifier: may return nil. And if it is you need to create your cell,s but dequeueReusableCellWithIdentifier: forIndexPath: will always return a valid cell, the catch is you need to tell it what kind of cell, that is what registerClass does.

Do this for both UITableViews.

- (void)viewDidLoad {
    [super viewDidLoad];

    [self.tableView registerClass:[ContactFieldCell class] forCellReuseIdentifier:@"ContactFieldCell"];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *thisCellIdentifier = @"ContactFieldCell";

    ContactFieldCell *cell = [self.tableView dequeueReusableCellWithIdentifier:thisCellIdentifier forIndexPath:indexPath];

    cell.delegate = self;
    cell.field = [self.card.sortedFields objectAtIndex:indexPath.row];

    return cell;
}

Upvotes: 1

vikingosegundo
vikingosegundo

Reputation: 52227

dequeueReusableCellWithIdentifier: does not create a cell if none was found for dequeueing.

Create a cell manually, or use dequeueReusableCellWithIdentifier:forIndexPath:

Upvotes: 2

Related Questions