如何在一个tableView中使用两个不同的自定义单元格?使用Storyboard和iOS 7。

3

我有两个自定义单元格,并且想在我的UITableView中显示2个部分。第一部分有一行,显示第一个自定义单元格,第二部分则显示从核心数据中提取的对象列表。

我应该如何实现“cellForRowAtIndexpath”方法呢?

这是我的一些代码:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{

// Return the number of sections.
return 2;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

// Return the number of rows in the section.
if (section == 0) {
    return 1;

} else if (section == 1) {
   //gastos is an array
   return [self.gastos count];  
}
return 0;
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath         *)indexPath
{

switch (indexPath.section) {
    case 0:
    {
        SaldoCelda *cell1 = [tableView dequeueReusableCellWithIdentifier:@"Cell1"      forIndexPath:indexPath];
        return cell1;
    }
    case 1:
    {
        static NSString *CellIdentifier = @"Cell";
        CeldaGasto *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier      forIndexPath:indexPath];

        NSManagedObject *gasto = [self.gastos objectAtIndex:indexPath.row];

        [cell.monto setText:[NSString stringWithFormat:@"%@ AR$", [gasto valueForKey:@"monto"]]];
        [cell.categoria setText:[NSString stringWithFormat:@"%@", [gasto valueForKey:@"categoria"]]];
        [cell.fecha setText:[NSString stringWithFormat:@"%@", [gasto valueForKey:@"fecha"]]];

        return cell;
    }
    default:
        break;
}
return 0;
}

这是我收到的错误信息:
断言失败在 -[UITableView _configureCellForDisplay:forIndexPath:],/SourceCache/UIKit_Sim/UIKit-2903.23/UITableView.m:6246 2014-03-05 01:02:57.181 Spendings[2897:70b] * 终止应用程序,原因:未捕获的异常 'NSInternalInconsistencyException',原因:'UITableView dataSource 必须从 tableView:cellForRowAtIndexPath: 返回一个 cell'。
感谢您的帮助!

3
阅读错误信息。你的 cellForRowAtIndexPath: 方法返回了 nil。问题可能出现在第0个或第1个情况中。使用调试器查看哪一个是问题所在。 - rmaddy
1
顺便说一句,对于以return结尾的switch语句中的情况,不需要使用break语句。在这些情况下,break语句永远不会被执行到。 - rmaddy
你是对的!在 switch 结束后,在方法末尾返回 0,可以吗? - JuanM.
实际上,cellForRowAtIndexPath 结尾的 return 0; 应该改为 return nil;,但从技术上讲它们是相同的。而且 return 0 总是无法到达。 - rmaddy
@JuanM. 已经检查了我的答案并尝试了一下。 - Charan Giri
我刚刚用你的问题制作了一个测试应用程序,它运行得很好,所以可能是你在单元格标识符方面出了一些问题,请检查你在故事板中是否正确引用了它。 - AntonijoDev
4个回答

3

我已经进行了测试,结果很好。以下是步骤:

  1. Create UITableViewController in storyBoard
  2. Drag and drop UITableViewCell on a UITableViewController below the cell that is already there
  3. Assign CellIdentifier to both cells (I used Cell1 and Cell2)
  4. Create 2 subclasses of UITableViewCell (I called them Cell1 and Cell2)
  5. Create subclass of UITableViewController and name it somehow
  6. in cellForRowAtIndexPath method:

    static NSString *CellIdentifier = @"Cell1";
    
    static NSString *CellIdentifier1 = @"Cell2";
    
    switch (indexPath.section) {
    
        case 0:
        {
            Cell1 *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
            return cell;
        }
            break;
        case 1:
        {
            Cell2 *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier1 forIndexPath:indexPath];
            return cell;
        }
            break;
    
        default:
            break;
    

    }

    return nil;
    

如您所见,实现方式与您的相同。

我唯一能够重现您的错误的方法是在 switch 块中返回 nil,而 dequeueReusableCellWithIdentifier 的文档说明如下:

此方法始终返回有效的单元格。

即使您弄乱了单元格标识符,您仍不会收到您发布的错误。因此我的结论是:

重新启动、清理项目、重新启动模拟器或类似操作可能会导致您的情况,因为根据文档,这种情况是不可能出现的...


0

你可以在一个xib文件中创建一组单元格,并使用它们的标识符在cellForRowAtindex中获取它们。现在,您可以设置它们的属性和数据。

static NSString *CellIdentifier = @"MyCellIdentifier";

MyCell *cell = (MyCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:CellIdentifier owner:self options:nil];
cell = (MyCell *)[nib objectAtIndex:0];

 cell1=(MyCell *)[nib objectAtIndex:1];
}

2
我认为使用XIB文件已经过时了,使用xCode 5和iOS 7,一切都可以通过storyboard来实现。 - JuanM.
我通常使用XIB文件来创建单元格,这样加载更简单,而且在设计单元格时更容易聚焦。但是我理解你想要仅使用Storyboard。也许你应该尝试一下。 - Jissay
你可以通过Storyboard的帮助来完成同样的事情。在Storyboard中,你需要从你的故事板文件中获取单元格的nib。 - Gourav Gupta

0
除了您在其中一个单元格中返回nil之外,您还有一个问题在于numberOfRowsInSection,您正在为第1个部分返回0行!!尽管您在cellForRowAtIndexPath中期望在此部分中获取行。

1
虽然你指出了 numberOfRowsInSection: 的实现是错误的,但这与崩溃无关。但它确实将问题缩小到了 cellForRowAtIndexPath:case 0: 代码的范畴。 - rmaddy
1
嗯,完全同意 ;) 但他仍然需要处理另一个问题。 - Tarek Hallak
或许是故事板的问题吗?我在故事板编辑器中有一个带有“静态单元格”的表视图,其部分等于“2”。第一部分只有一个单元格,其标识符为Cell1。 - JuanM.
1
首先,这个表格不是一个“静态单元格”内容,与你的问题无关(我猜你已经忽略了)。其次,你需要为第二个区域创建一个原型单元格,并将其注册为“Cell”,或在cellForRowAtIndexPath中初始化它。 - Tarek Hallak
1
很高兴这样,但是单元格高度另当别论,可以使用委托来更改:- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 如果 (indexpathe.section == 0 && indexpathe.row == 0) 返回50.0; 否则返回100; } - Tarek Hallak
显示剩余6条评论

-3
尝试一下,我正在修改你的代码。
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 2;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
if (section == 0) {
  return 1;
}
else if (section == 2) {
//gastos is an array
return [self.gastos count];  
}
//return 0; you should not write this because at the end of execution of this method it will return 0
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath         *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
switch (indexPath.section) {
case 0:
{
SaldoCelda *cell1 = [tableView dequeueReusableCellWithIdentifier:@"Cell1"      forIndexPath:indexPath];
cell=cell1;
    break; 
}
case 1:
{
static NSString *CellIdentifier = @"Cell";
CeldaGasto *cell2 = [tableView dequeueReusableCellWithIdentifier:CellIdentifier      forIndexPath:indexPath];

NSManagedObject *gasto = [self.gastos objectAtIndex:indexPath.row];
[cell.monto setText:[NSString stringWithFormat:@"%@ AR$", [gasto valueForKey:@"monto"]]];
[cell.categoria setText:[NSString stringWithFormat:@"%@", [gasto valueForKey:@"categoria"]]];
[cell.fecha setText:[NSString stringWithFormat:@"%@", [gasto valueForKey:@"fecha"]]];
cell=cell2;
break;
}
default:
break;
}
return cell;
//return 0; remove this in your code
}

希望这能有所帮助


这些更改都是不必要的,实际上会让代码更加混乱。而且这些更改都无法解决问题。 - rmaddy
@rmaddy,是哪部分代码让你感到困惑了?return 0; 的意思是你将 nil 返回给了单元格和行... - Charan Giri
1
我并不困惑。return 语句永远不会被执行到。表格有两个部分,因此 switchcase 0case 1 分别处理这两个部分。两者都会创建并返回一个单元格。default 永远不会被执行到。方法末尾的 return 语句也永远不会被执行到。原帖中的代码比你的提案更加简洁。 - rmaddy
谢谢Charan,但我已经在之前的答案中解决了部分问题。我明白了@rmaddy所说的return永远不会被执行。 - JuanM.
@rmaddy 当 switch 条件为真时,默认情况永远不会被触发。在第 0 和 1 节中,我将 cell1 分配给 cell,将 cell2 分配给 cell,并在最后返回它作为 return cell;break 仅用于中断 switch,而不是 cell 配置方法。因此,它将到达 return cell 语句。如果我理解有误,请您解释一下。 - Charan Giri
抱歉,我在谈论OP的代码。我的整个观点是你提出的更改是不必要的,而且更加复杂。更重要的是,它根本没有解决问题。 - rmaddy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接