【问题标题】:Assertion failure in dequeueReusableCellWithIdentifier:forIndexPath:dequeueReusableCellWithIdentifier:forIndexPath 中的断言失败:
【发布时间】:2012-09-26 02:44:54
【问题描述】:

所以我正在为我的学校制作一个 rss 阅读器并完成了代码。我运行了测试,它给了我这个错误。这是它所指的代码:

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

        cell = 
         [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle  
                                reuseIdentifier:CellIdentifier];

    }

这是输出中的错误:

2012-10-04 20:13:05.356 Reader[4390:c07] * 中的断言失败 -[UITableView dequeueReusableCellWithIdentifier:forIndexPath:],/SourceCache/UIKit_Sim/UIKit-2372/UITableView.m:4460 2012-10-04 20:13:05.357 Reader[4390:c07] * 由于未捕获而终止应用程序 异常'NSInternalInconsistencyException',原因:'无法 将具有标识符 Cell 的单元出列 - 必须注册一个 nib 或一个类 用于标识符或连接故事板中的原型单元' * 第一次抛出调用栈:(0x1c91012 0x10cee7e 0x1c90e78 0xb64f35 0xc7d14 0x39ff 0xd0f4b 0xd101f 0xb980b 0xca19b 0x6692d 0x10e26b0 0x228dfc0 0x228233c 0x228deaf 0x1058cd 0x4e1a6 0x4ccbf 0x4cbd9 0x4be34 0x4bc6e 0x4ca29 0x4f922 0xf9fec 0x46bc4 0x47311 0x2cf3 0x137b7 0x13da7 0x14fab 0x26315 0x2724b 0x18cf8 0x1becdf9 0x1becad0 0x1c06bf5 0x1c06962 0x1c37bb6 0x1c36f44 0x1c36e1b 0x147da 0x1665c 0x2a02 0x2935) libc++abi.dylib:终止调用抛出异常

这是它在错误屏幕中显示的代码:

int main(int argc, char *argv[])
{
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

请帮忙!

【问题讨论】:

标签: ios objective-c uitableview


【解决方案1】:

您正在使用dequeueReusableCellWithIdentifier:forIndexPath: 方法。该方法的documentation 表示:

重要提示:在调用此方法之前,您必须使用registerNib:forCellReuseIdentifier:registerClass:forCellReuseIdentifier: 方法注册一个类或nib 文件。

您没有为重用标识符 "Cell" 注册 nib 或类。

查看您的代码,您似乎希望 dequeue 方法返回 nil,如果它没有单元格可以给您。您需要使用 dequeueReusableCellWithIdentifier: 来实现该行为:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

注意dequeueReusableCellWithIdentifier:dequeueReusableCellWithIdentifier:forIndexPath: 是不同的方法。有关the formerthe latter,请参阅文档。

如果您想了解为什么要使用 dequeueReusableCellWithIdentifier:forIndexPath:check out this Q&A

【讨论】:

  • 天啊。为什么 Xcode 的 UITableViewController 的默认模板会自动为您提供 dequeueReusableCellWithIdentifier:forIndexPath:?太没用了。
  • dequeueReusableCellWithIdentifer:forIndexPath:(在 iOS6 中引入)是一个很好的改进,因为您不需要检查单元格是否为 nil。 (所以UITableViewControllerUICollectionView 的工作方式相似)但是,是的,令人讨厌的是,模板中没有对此更改进行注释,并且断言/崩溃消息没有更多帮助。
  • 至少你会认为它会默认为 UITableViewCell 而不是内爆。巴卡。
  • 这个答案的最后一行是金句:当我应该使用dequeueReusableCellWithIdentifier:时,我已经不止一次使用dequeueReusableCellWithIdentifier:forIndexPath:被咬了。
  • 这个答案很完美。我有一个问题:我有一个 tableViewController 作为我的初始视图控制器。在 didSelectRow... 我将另一个 tableViewController 推到导航堆栈上。为什么我只需要为第二个 tableViewController 注册一个单元格,而不是初始的?
【解决方案2】:

我将补充一点,Xcode 4.5 包含新的 dequeueReusableCellWithIdentifier:forIndexPath:
在其默认模板代码中 - 对于期望较旧的 dequeueReusableCellWithIdentifier: 方法的开发人员来说,这是一个潜在的陷阱。

【讨论】:

  • 蜇我!现在我会知道的更好。 ;)
【解决方案3】:

替换时我遇到了同样的问题
static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

   if (cell==nil) {
        cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];

    }

解决了

【讨论】:

  • 谢谢。这只是让我头疼。 =)
  • 提示:如果你使用 -(id)dequeueReusableCellWithIdentifier:forIndexPath:,则不需要验证单元格是否为 nil。 (IOS6>)
  • 只是让我头疼。 =)
【解决方案4】:

我认为这个错误是关于为标识符注册你的笔尖或类。

这样您就可以在 tableView:cellForRowAtIndexPath 函数中保留您正在做的事情,只需将下面的代码添加到您的 viewDidLoad 中:

[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"Cell"];

它对我有用。希望对您有所帮助。

【讨论】:

  • 一个小问题 - 确保重用标识符与您在 Storyboard 设置中为相关单元格设置的内容相匹配。
  • 只是为了在稍微不同的用例中添加这一点,我在我的 SplitViewController 的主视图中重新选择了一行。此重新选择行逻辑位于 viewDidLoad 中,将此逻辑移至 viewDidAppear 已修复。
  • 无法进入 cell==nil ,所以我的 tableview 单元格总是 nil。
  • swift 3.0: self.tableView.register(UITableViewCell.classForCoder(), forCellReuseIdentifier:"Cell");
【解决方案5】:

在您的故事板中,您应该将原型单元格的“标识符”设置为与您的 CellReuseIdentifier“单元格”相同。那么您将不会收到该消息或需要调用该 registerClass: 函数。

【讨论】:

  • 明白了! “100 upvotes”按钮在哪里。这是真正的解决方案。
  • 您会认为将新的 tableView 添加到情节提要中将为您提供默认标识符 - 'Cell'。它很容易被忽视,特别是如果您在 tableView:cellForRowAtIndexPath 中使用所谓的“免费代码”!
【解决方案6】:

如果您要使用 自定义静态单元格,只需评论此方法:

//- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
//    static NSString *CellIdentifier = @"notificationCell";
//    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
//    return cell;
//}

并在情节提要的“Attributes Inspector”处为单元格指定一个标识符。

【讨论】:

    【解决方案7】:

    昨晚我花了几个小时来弄清楚为什么我以编程方式生成的表在 [myTable setDataSource:self] 上崩溃了;可以注释掉并弹出一个空表,但每次我尝试访问数据源时都会崩溃;

    我在 h 文件中设置了委派:@interface myViewController : UIViewController

    我的实现中有数据源代码,但仍然 BOOM!,每次都崩溃!谢谢“xxd”(nr 9):添加那行代码为我解决了这个问题!事实上,我是从 IBAction 按钮启动一个表格,所以这是我的完整代码:

        - (IBAction)tapButton:(id)sender {
    
        UIViewController* popoverContent = [[UIViewController alloc]init];
    
        UIView* popoverView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 300)];
        popoverView.backgroundColor = [UIColor greenColor];
        popoverContent.view = popoverView;
    
        //Add the table
        UITableView *table = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 200, 300)         style:UITableViewStylePlain];
    
       // NEXT THE LINE THAT SAVED MY SANITY Without it the program built OK, but crashed when      tapping the button!
    
        [table registerClass:[UITableViewCell class] forCellReuseIdentifier:@"Cell"];
        table.delegate=self;
        [table setDataSource:self];
        [popoverView addSubview:table];
        popoverContent.contentSizeForViewInPopover =
        CGSizeMake(200, 300);
    
        //create a popover controller
        popoverController3 = [[UIPopoverController alloc]
                              initWithContentViewController:popoverContent];
        CGRect popRect = CGRectMake(self.tapButton.frame.origin.x,
                                    self.tapButton.frame.origin.y,
                                    self.tapButton.frame.size.width,
                                    self.tapButton.frame.size.height);
    
    
        [popoverController3 presentPopoverFromRect:popRect inView:self.view   permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
    
    
    
       }
    
    
       #Table view data source in same m file
    
       - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
       {
        NSLog(@"Sections in table");
        // Return the number of sections.
        return 1;
       }
    
       - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
      {
        NSLog(@"Rows in table");
    
        // Return the number of rows in the section.
        return myArray.count;
       }
    
       - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath    *)indexPath
        {
        static NSString *CellIdentifier = @"Cell";
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
    
        NSString *myValue;
    
        //This is just some test array I created:
        myValue=[myArray objectAtIndex:indexPath.row];
    
        cell.textLabel.text=myValue;
        UIFont *myFont = [ UIFont fontWithName: @"Arial" size: 12.0 ];
        cell.textLabel.font  = myFont;
    
        return cell;
       }
    

    顺便说一句:如果您想将弹出框锚定到按钮上,则该按钮必须作为 IBAction 和 IBOutlet 链接。

    UIPopoverController *popoverController3在H文件中直接声明在{}之间的@interface之后

    【讨论】:

      【解决方案8】:

      虽然这个问题已经相当老了,但还有另一种可能性: 如果您使用 Storyboard,您只需在 Storyboard 中设置 CellIdentifier。

      因此,如果您的 CellIdentifier 是“Cell”,只需设置“Identifier”属性:

      这样做后请务必清理您的构建。 XCode 有时会在 Storyboard 更新方面出现一些问题

      【讨论】:

      • 你太棒了,清洁很重要! :D
      • 注意 - 如果您使用“Cell”以外的标识符,您还需要更改 cellForRowAtIndexPath 方法以在以下行中使用此标识符: static NSString *CellIdentifier = @"MyCellIdentifier";
      • 一个重要的补充:表格视图的“内容”属性必须设置为“动态原型”,而不是“静态单元”
      • 这个答案需要更高。很有帮助
      • 更新 Identifier 属性后,清理构建是必不可少的。谢谢!
      【解决方案9】:

      问题很可能是因为您在故事板中配置了自定义UITableViewCell,但您没有使用故事板来实例化使用此UITableViewCellUITableViewController。例如,在 MainStoryboard 中,您有一个名为 MyTableViewControllerUITableViewController 子类和一个名为 MyTableViewCell 的自定义动态 UITableViewCell,其标识符 id 为“MyCell”。

      如果您像这样创建自定义UITableViewController

       MyTableViewController *myTableViewController = [[MyTableViewController alloc] init];
      

      它不会自动为您注册您的自定义 tableviewcell。您必须手动注册。

      但是如果你使用storyboard来实例化MyTableViewController,像这样:

      UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
      MyTableViewController *myTableViewController = [storyboard  instantiateViewControllerWithIdentifier:@"MyTableViewController"];
      

      好事发生了! UITableViewController 将自动注册您在情节提要中为您定义的自定义表格视图单元格。

      在您的委托方法“cellForRowAtIndexPath”中,您可以像这样创建表格视图单元格:

      - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
      static NSString *CellIdentifier = @"MyCell";
      UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
      
      //Configure your cell here ...
      
      return cell;
      }
      

      dequeueReusableCellWithIdentifier 如果回收队列中没有可重复使用的单元格,将自动为您创建新单元格。

      那么你就完成了!

      【讨论】:

      • 使用instantiateViewControllerWithIdentifier 来初始化我的viewController 的提示拯救了我的一天!
      • 拯救了我的一天:原型单元在相邻的 VC 中,有一张桌子
      • 在我的情况下这是合理的原因。
      【解决方案10】:

      FWIW,当我忘记在情节提要中设置单元格标识符时,我遇到了同样的错误。如果这是您的问题,那么在情节提要中单击表格视图单元格并在属性编辑器中设置单元格标识符。确保您在此处设置的单元格标识符与

      相同
      static NSString *CellIdentifier = @"YourCellIdenifier";
      

      【讨论】:

        【解决方案11】:

        我在 Storyboard 中正确设置了所有内容并进行了干净的构建,但一直收到错误“必须为标识符注册一个 nib 或一个类或连接故事板中的原型单元

        [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"Cell"];
        

        纠正了错误,但我仍然不知所措。我没有使用“自定义单元格”,只是一个嵌入了 tableview 的视图。我已将视图控制器声明为委托和数据源,并确保单元格标识符在文件中匹配。这是怎么回事?

        【讨论】:

          【解决方案12】:

          这对某些人来说可能看起来很愚蠢,但它让我明白了。我收到了这个错误,对我来说问题是我试图使用静态单元格,然后动态添加更多内容。如果您调用此方法,您的单元格需要是动态原型。选择情节提要中的单元格并在属性检查器下,第一件事是“内容”,您应该选择动态原型而不是静态原型。

          【讨论】:

          • 谢谢!这正是我的问题。
          【解决方案13】:

          我遇到了同样的问题,遇到了同样的错误,对我来说它是这样工作的:

          [self.tableView registerNib:[UINib nibWithNibName:CELL_NIB_HERE bundle: nil] forCellReuseIdentifier:CELL_IDENTIFIER_HERE];
          

          也许它对其他人有用。

          【讨论】:

            【解决方案14】:

            Swift 2.0 解决方案:

            你需要进入你的属性检查器并为你的单元格标识符添加一个名称:

            然后你需要像这样使你的标识符与你的出队匹配:

            let cell2 = tableView.dequeueReusableCellWithIdentifier("ButtonCell", forIndexPath: indexPath) as! ButtonCell
            

            或者

            如果您正在使用 nib,您可能需要在 cellForRowAtIndexPath 中注册您的课程:

            override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {       
            
                tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "SwitchCell")
            
                // included for context            
                let cell = tableView.dequeueReusableCellWithIdentifier("SwitchCell", forIndexPath:indexPath) as! SwitchCell
            
                //... continue    
            }
            

            Apples's UITableView Class Reference says:

            在将任何单元格出列之前,调用此方法或 registerNib:forCellReuseIdentifier: 方法告诉表视图如何 创建新的细胞。如果指定类型的单元格当前不是 在重用队列中,表视图使用提供的信息 自动创建一个新的单元格对象。

            如果您之前注册了具有相同重用性的类或 nib 文件 标识符,您在 cellClass 参数中指定的类替换 旧条目。如果您愿意,可以为 cellClass 指定 nil 从指定的重用标识符中注销类。

            这是来自 Apple Swift 2.0 框架的代码:

            // Beginning in iOS 6, clients can register a nib or class for each cell.
            // If all reuse identifiers are registered, use the newer -dequeueReusableCellWithIdentifier:forIndexPath: to guarantee that a cell instance is returned.
            // Instances returned from the new dequeue method will also be properly sized when they are returned.
            
            @available(iOS 5.0, *)
            func registerNib(nib: UINib?, forCellReuseIdentifier identifier: String)
            
            @available(iOS 6.0, *)
            func registerClass(cellClass: AnyClass?, forCellReuseIdentifier identifier: String)
            

            【讨论】:

            • 我不明白SwitchCell.self 来自哪里?
            • @GertCuykens SwitchCell 是我的自定义 UITableViewCell
            • 我现在不在我的 Mac 上,但我回家后肯定可以更新它。
            • UITableViewCell.self 替换它似乎对我有用。也许在答案中添加注释
            • @GertCuykens 感谢您指出这一点,我已将 SwitchCell.self 更改为 UITableViewCell.self
            【解决方案15】:

            只是答案的补充: 可能有一段时间你把所有东西都设置好了,但你可能会不小心在.xib 中添加一些其他 UI,比如 UIButton: 删除多余的 UI 即可。

            【讨论】:

              【解决方案16】:

              就我而言,当我打电话给deselectRowAtIndexPath:时发生了崩溃

              线路是[tableView deselectRowAtIndexPath:indexPath animated:YES];

              将其更改为[self.tableView deselectRowAtIndexPath:indexPath animated:YES]; 修复了我的问题!

              希望这对任何人都有帮助

              【讨论】:

                【解决方案17】:

                在 Swift 中,可以通过在您的

                中添加以下代码来解决此问题

                viewDidLoad

                方法。

                tableView.registerClass(UITableViewCell.classForKeyedArchiver(), forCellReuseIdentifier: "your_reuse_identifier")
                

                【讨论】:

                  【解决方案18】:

                  我在 Objective C 和 Swift 中都给你答案。在此之前我想说

                  如果我们使用dequeueReusableCellWithIdentifier:forIndexPath:,我们必须在调用此方法之前使用 registerNib:forCellReuseIdentifier: 或 registerClass:forCellReuseIdentifier: 方法注册一个类或 nib 文件 Apple Documnetation Says

                  所以我们添加registerNib:forCellReuseIdentifier: or registerClass:forCellReuseIdentifier:

                  一旦我们为指定的标识符注册了一个类并且必须创建一个新单元格,此方法通过调用其 initWithStyle:reuseIdentifier: 方法来初始化该单元格。对于基于 nib 的单元格,此方法从提供的 nib 文件加载单元格对象。如果现有单元格可供重用,则此方法将调用该单元格的 prepareForReuse 方法。

                  在 viewDidLoad 方法中我们应该注册单元格

                  目标 C

                  选项 1:

                  [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"];
                  

                  选项 2:

                  [self.tableView registerNib:[UINib nibWithNibName:@"CustomCell" bundle:nil] forCellReuseIdentifier:@"cell"];
                  

                  在上面的代码nibWithNibName:@"CustomCell" 中给出你的笔尖名称而不是我的笔尖名称CustomCell

                  SWIFT

                  选项 1:

                  tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
                  

                  选项 2:

                  tableView.registerNib(UINib(nibName: "NameInput", bundle: nil), forCellReuseIdentifier: "Cell") 
                  

                  在上面的代码nibName:"NameInput" 中给出你的笔尖名称

                  【讨论】:

                    【解决方案19】:

                    使用 Swift 3.0:

                    override func viewDidLoad() {
                    super.viewDidLoad()
                    
                    self.myList.register(UINib(nibName: "MyTableViewCell", bundle: nil), forCellReuseIdentifier: "Cell")
                    }
                    
                    
                    
                    public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
                    let cell = myList.dequeueReusableCell(withIdentifier: "Cell", for: indexPath as IndexPath) as! MyTableViewCell
                    
                    return cell
                    }
                    

                    【讨论】:

                      【解决方案20】:

                      确保故事板中单元格的 CellIdentifier == 标识符,两个名称相同。希望这对你有用

                      【讨论】:

                        【解决方案21】:

                        遇到此错误,因为单元重用标识符错误——一个新手错误,但它发生了: 1. 确保单元格重复使用标识符没有拼写错误或缺少字母。 2. 同样,不要忘记大小写计数。 3. 零不是“O”(哦)

                        【讨论】:

                          【解决方案22】:

                          您必须注意,当使用 interface builder 并创建一个包含 一个 单元格的 Xib(笔尖)时,还会创建一个 placeholder 指向将要使用的类用过的。这意味着,当您在一个 Xib 文件中放置两个 UITableViewCell 时,您可能会遇到完全相同的问题,从而导致 *** Assertion failure ...。占位符机制不起作用,然后会感到困惑。而是在一个 Xib 中放置不同的占位符继续阅读..

                          最简单的解决方案(即使这看起来有点简单)是一次将一个 Cell放入一个 Xib。 IB 将为您创建一个占位符,然后所有工作都按预期进行。但这会直接导致一行额外的代码,因为你需要加载正确的 nib/xib 来请求它所在的重用标识单元。 因此,下面的示例代码将重点放在一个 tableview 中使用多个 Cell Identifiers,其中 Assertion Failure 很常见。

                          // possibly above class implementation
                          static NSString *firstCellIdentifier = @"firstCellIdentifier";
                          static NSString *secondCellIdentifier = @"secondCellIdentifier";
                          
                          // possibly in -(instancetype)init 
                          UINib *firstNib = [UINib nibWithNibName:@"FirstCell" bundle:nil];
                          [self.tableView registerNib:firstNib forCellReuseIdentifier:firstCellIdentifier];
                          UINib *secondNib = [UINib nibWithNibName:@"SecondCell" bundle:nil];
                          [self.tableView registerNib:secondNib forCellReuseIdentifier:secondCellIdentifier];
                          

                          在一个 UITableView 中使用两个 CellIdentifier 的另一个问题是必须注意行高和/或节高。当然,两个单元格可以有不同的高度。

                          重用注册类时,代码应该看起来不同。

                          当您的单元位于 Storyboard 而不是 Xib 中时,“简单解决方案”看起来也大不相同。注意占位符。

                          还请记住,界面构建器文件具有版本差异,需要设置为您的目标操作系统版本支持的版本。即使您可能很幸运,您放置在 Xib 中的特定功能自上一个 IB 版本以来没有更改,并且还没有引发错误。因此,使用 IB 制作的 Xib 设置为与 iOS 13+ 兼容,但用于在早期版本 iOS 12.4 上编译的目标中也会引起麻烦并最终导致断言失败。

                          【讨论】:

                            猜你喜欢
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 2013-12-29
                            • 2011-05-27
                            • 2017-08-07
                            • 2012-08-01
                            相关资源
                            最近更新 更多