Reputation: 4843
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
Reputation: 4271
UITableView
s 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 delegate
s and dataSource
s 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
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
Reputation: 52227
dequeueReusableCellWithIdentifier:
does not create a cell if none was found for dequeueing.
Create a cell manually, or use dequeueReusableCellWithIdentifier:forIndexPath:
Upvotes: 2