- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"myCel开发者_开发问答l";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
NSArray *allSections =[self.tableDataSource allKeys];
NSArray *aSection = [self.tableDataSource objectForKey:[allSections objectAtIndex:indexPath.section]];
NSMutableDictionary *item = [aSection objectAtIndex:indexPath.row] ;
if (cell == nil) {
/* Trace 1 */
NSLog(@"Init: Section: %i - Row: %i", indexPath.section, indexPath.row);
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
UISwitch *mySwitch = [[UISwitch alloc] init];
[mySwitch addTarget:self action:@selector(checkButtonTapped:) forControlEvents:UIControlEventValueChanged];
[mySwitch setOn:NO animated:NO];
cell.accessoryView = mySwitch;
cell.accessoryView.tag = [[item objectForKey:@"ID"] integerValue];
cell.textLabel.text = [item objectForKey:@"Name"];
[item setObject:cell forKey:@"cell"];
} else {
/* Trace 2 */
NSLog(@"Done: Section: %i - Row: %i", indexPath.section, indexPath.row);
cell = [item objectForKey:@"cell"];
}
return cell;}
Hello all,
I'm struggling with a UITableView + accessories which is crashing "sometime" at runtime. The main code tableView:cellForRowAtIndexPath is just above and, as far as I understand, is really based on the standard pattern for a UITableView.
My dataSource is small, it's just a 2 sections dataset, one of 6 lines and another is only 2 lines. All the methods about number of rows in section and number of sections are implemented.
User interface in IB has the required connections and actually everything is working fine. The UITableView in IB is slightly smaller the the main view (there is 2 buttons below the tableview). When I run the app, I can see in the view the first 6 rows (first section), but the last 2 rows (second section) are hidden. Of course, if I scroll down, last 2 rows will appear ...
The issue is when I reduce the UITableView outlet size in IB. If the outlet displays only 2 or 3 rows from the first section at runtime, then the App will crash if I scroll down. The crash will occur at the first row of the second section. Only change with the previous situation is the IB outlet size, nothing has been changed in the code.
Error message in the console is :
* Assertion failure in -[UITableView _createPreparedCellForGlobalRow:withIndexPath:], /SourceCache/UIKit_Sim/UIKit-1448.89/UITableView.m:5678 2011-07-04 02:08:46.713 iWiR Client[95362:207] * Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath:'
If you look at the code, you will see that there is 2 NSLog traces. Normal behavior for the code is that "Trace 1" will be displayed in the console for the first display of the row, and then, if I scroll up and down, that will be "trace 2". This is what the case if the IBoutlet of the UITableView is "big enough", but, as I said, if I reduce the size of the outlet, console will display "Trace 2" even for the first display of the row.
I hope these (long) explanations are clear enough, and tks a bunch for your help ...
Cheers, Pierre
Imagine a table view with 6 rows out of which 2 rows are visible. As you scroll down to get the 4th row onto the visible region, cell
that you dequeued from the table view will not be nil
so the else
clause will be executed.
cell = [item objectForKey:@"cell"];
At this point there is not object set for the key cell
. So objectForKey:
will return nil
and cell will be nil
which you return at the end of the method. This is the reason for the error that says 'UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath:'
as you are returning nil
here.
You are not reusing cells via mechanism provided by UITableView
. Your method should more be like,
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSArray *allSections =[self.tableDataSource allKeys];
NSArray *aSection = [self.tableDataSource objectForKey:[allSections objectAtIndex:indexPath.section]];
NSMutableDictionary *item = [aSection objectAtIndex:indexPath.row] ;
UITableViewCell *cell = [item objectForKey:@"cell"];
if (cell == nil) {
NSLog(@"Init: Section: %i - Row: %i", indexPath.section, indexPath.row);
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil] autorelease];
[..]
}
return cell;
}
精彩评论