ChatGPT解决这个技术问题 Extra ChatGPT

unable to dequeue a cell with identifier Cell - must register a nib or a class for the identifier or connect a prototype cell in a storyboard

My UITableViewController is causing a crash with the following error message:

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'unable to dequeue a cell with identifier Cell - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'

I understand that I need to register a nib or a class but I don't understand 'where or how?'.

import UIKit

class NotesListViewController: UITableViewController {

    @IBOutlet weak var menuButton: UIBarButtonItem!
    
  override func viewDidLoad() {
    super.viewDidLoad()
    NSNotificationCenter.defaultCenter().addObserver(self,
      selector: "preferredContentSizeChanged:",
      name: UIContentSizeCategoryDidChangeNotification,
      object: nil)
    
    // Side Menu
    
    if self.revealViewController() != nil {
        menuButton.target = self.revealViewController()
        menuButton.action = "revealToggle:"
        self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
    }
    
  }

  override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)
    // whenever this view controller appears, reload the table. This allows it to reflect any changes
    // made whilst editing notes
    tableView.reloadData()
  }

  func preferredContentSizeChanged(notification: NSNotification) {
    tableView.reloadData()
  }

  // #pragma mark - Table view data source

  override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return 1
  }

  override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return notes.count
  }

  override func tableView(tableView: UITableView, cellForRowAtIndexPath   indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
    
    let note = notes[indexPath.row]
    let font = UIFont.preferredFontForTextStyle(UIFontTextStyleHeadline)
    let textColor = UIColor(red: 0.175, green: 0.458, blue: 0.831, alpha: 1)
    let attributes = [
      NSForegroundColorAttributeName : textColor,
      NSFontAttributeName : font,
      NSTextEffectAttributeName : NSTextEffectLetterpressStyle
    ]
    let attributedString = NSAttributedString(string: note.title, attributes: attributes)

    cell.textLabel?.font = UIFont.preferredFontForTextStyle(UIFontTextStyleHeadline)

    cell.textLabel?.attributedText = attributedString
    
    return cell
  }

  let label: UILabel = {
    let temporaryLabel = UILabel(frame: CGRect(x: 0, y: 0, width: Int.max, height: Int.max))
    temporaryLabel.text = "test"
    return temporaryLabel
    }()

  override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    label.font = UIFont.preferredFontForTextStyle(UIFontTextStyleHeadline)
    label.sizeToFit()
    return label.frame.height * 1.7
  }

  override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
    if editingStyle == .Delete {
      notes.removeAtIndex(indexPath.row)
      tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
    }
  }

  // #pragma mark - Navigation

  // In a storyboard-based application, you will often want to do a little preparation before navigation
  override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
    if let editorVC = segue.destinationViewController as? NoteEditorViewController {

      if "CellSelected" == segue.identifier {
        if let path = tableView.indexPathForSelectedRow() {
          editorVC.note = notes[path.row]
        }
      } else if "AddNewNote" == segue.identifier {
        let note = Note(text: " ")
        editorVC.note = note
        notes.append(note)
      }
    }
  }

}
Watch out for the confusing "Restoration ID" - which is nothing! Click the FOURTH tab at the top right, NOT the THIRD tab!!

T
Tamás Sengel

You can register a class for your UITableViewCell like this:

With Swift 3+:

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

With Swift 2.2:

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

Make sure same identifier "cell" is also copied at your storyboard's UITableViewCell.

"self" is for getting the class use the class name followed by .self.


Where do you put this?
in viewDidLoad()
If you are using an xib in your custom cell, you will have to register it like this: tableView.register(UINib.init(nibName: "CustomCell", bundle: nil), forCellReuseIdentifier: "CustomCellIdentifier")
the swift 3+ solution above worked for me in swift 5
D
Derlin

Have you set the Table Cell identifier to "Cell" in your storyboard?

Or have you set the class for the UITableViewController to your class in that scene?


I forgot to set the class for my view controller in the scene. thanks
J
Jaywant Khedkar

This worked for me, May help you too :

Swift 4+ :

self.tableView.register(UITableViewCell.self, forCellWithReuseIdentifier: "cell")

Swift 3 :

self.tableView.register(UITableViewCell.classForKeyedArchiver(), forCellReuseIdentifier: "Cell")

Swift 2.2 :

self.tableView.registerClass(UITableViewCell.classForKeyedArchiver(), forCellReuseIdentifier: "Cell")

We have to Set Identifier property to Table View Cell as per below image,

https://i.stack.imgur.com/rjx3f.png


Just so simple :-)
it worked! I was setting the ID in the idendity inspector but pasting it in the attribute inspector worked for me
God bless You! Saved a couple of my lifetime
M
MacInnis

I had this issue today which was solved by selecting Product -> Clean. I was so confused since my code was proper. The problem started from using command-Z too many times :)


Seriously spent over an hour trying to debug this. Thank you :)
Of course it works in combination with defining the identifier in the storyboard (see next answer)
x
xhinoda

y my case i solved this by named it in the "Identifier" property of Table View Cell:

https://i.stack.imgur.com/39Ryb.png

Don't forgot: to declare in your Class: UITableViewDataSource

 let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as UITableViewCell

this picture is mismatching but it gave some hint.
it's a little out-dated just
F
Fattie

Just drag a cell (as you did for TableViewController) and add in to it just by releasing the cell on TableViewController. Click on the cell and.Go to its attributes inspector and set its identifier as "Cell".Hope it works.

Don't forget you want Identifier on the Attributes Inspector.

(NOT the "Restoration ID" on the "Identity Inspector" !)


Watch out for the confusing "Restoration ID" - which is nothing! Click the FOURTH tab at the top right, NOT the THIRD tab!!!
Years of coding in xcode and I still make the same mistake. Thanks man :)
R
Rohit Singh

Match the identifier name at both places

This error occurs when the identifier name of the Tablecell is different in the Swift file and in the Storyboard.

For example, the identifier is placecellIdentifier in my case.

1) The Swift File

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "placecellIdentifier", for: indexPath)
    
    // Your code 

    return cell
}

2) The Storyboard

https://i.stack.imgur.com/jv0oK.png


P
Peter Honeder

One more reason for this issue to happen is an earlier problem. When showing a new ViewController, instantiating the target ViewController directly will of course not load the prototype cells from the StoryBoard. The correct solution should always be to instantiate the view controller through the story board like this:

storyboard?.instantiateViewController(withIdentifier: "some_identifier")

Yes!! It's true!! This happened to me because I transitioned to the ViewController which is located in different Storyboard just with: self.present(MyViewController, animated: false, completion:nil). And it looks like it`s really doesn't download the prototype! I've tried to start with MyViewController directly and it works right! It also works when I'm registering NIB for my cell in viewDidLoad of target ViewController.
a
ak_ninan

In Swift 3.0, register a class for your UITableViewCell like this :

tableView.register(UINib(nibName: "YourCellXibName", bundle: nil), forCellReuseIdentifier: "Cell")

R
Reza Dehnavi

I had the same problem. This issue worked for me. In storyboard select your table view and change it from static cells into dynamic cells.


N
Noor Ali Butt

My problem was I was registering table view cell inside dispatch queue asynchronously. If you have registered table view source and delegate reference in storyboard then dispatch queue would delay the registration of cell as name suggests it will happen asynchronously and your table view is looking for the cells.

DispatchQueue.main.async {
    self.tableView.register(CampaignTableViewCell.self, forCellReuseIdentifier: CampaignTableViewCell.identifier())
    self.tableView.reloadData()
}

Either you shouldn't use dispatch queue for registration OR do this:

DispatchQueue.main.async {
    self.tableView.dataSource = self
    self.tableView.delegate = self
    self.tableView.register(CampaignTableViewCell.self, forCellReuseIdentifier: CampaignTableViewCell.identifier())
    self.tableView.reloadData()
}

J
JeffreyWang23

Stupid mistake:

make sure you add register(TableViewCell.self, forCellReuseIdentifier: "Cell") instead of register(TableViewCell.self, forHeaderFooterViewReuseIdentifier: "Cell")


S
Scaraux

If you defined your cell through the Interface Builder, by placing a cell inside your UICollectionView, or UITableView :

Make sure you binded the cell with an actual class you created, and very important, that you checked "Inherit module from target"


A
ABS

It used to work on swift 3 and swift 4 but now its not working.

like

self.tableView.register(MyTestTableViewCell.self, forCellReuseIdentifier: "cell")

So I have tried the most of the solutions mentioned above in swift 5 but did not get any luck.

Finally I tried this solution and it worked for me.

override func viewDidLoad() 
{

    tableView.register(UINib.init(nibName: "MyTestTableViewCell", bundle: nil), forCellReuseIdentifier: "myTestTableViewCell")
}

M
Md Imran Choudhury

There is two way you can define cell. If your table cell is inside on your ViewControllern then get the cell this way:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath) as! TableViewCell
        // write your code here 
        return cell
}

But if you define cell outside of your ViewController then call the sell this way:

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = Bundle.main.loadNibNamed("TableViewCell", owner: self, options: nil)?.first as! TableViewCell
        // write your code here
        return cell
    }

And as everyone said don't forget to set your cell identifier:

https://i.stack.imgur.com/T0JbN.png


M
Maria Chen

I just met the same issue and see this post. For me it's because I forgot the set the identifier of cell, also as mentioned in other answers. What I want to say is that if you are using the storyboard to load custom cell we don't need to register the table view cell in code, which can cause other problems.

See this post for detail:

Custom table view cell: IBOutlet label is nil


s
swiftBoy

Swift 5

you need to use UINib method to register cell in viewDidLoad

override func viewDidLoad() 
{
    super.viewDidLoad()
    // Do any additional setup after loading the view.

    //register table view cell        
    tableView.register(UINib.init(nibName: "CustomTableViewCell", bundle: nil), forCellReuseIdentifier: "CustomTableViewCell")
}

V
Visal Rajapakse

I had the same issue where I registered my custom UITableViewCell classes within the viewDidLoad() which threw this error. To fix it what I did was registered the cells within the didSet property observer, as shown below

@IBOutlet tableview : UITableView! {
    didSet {
        tableview.register(CustomCell.self, forCellReuseIdentifier: "Cell")
    }
}

Z
Zoe stands with Ukraine

Just for those new to iOS buddies (like me) who decided to have multiple cells and in a different xib file, the solution is not to have identifier but to do this:

let cell = Bundle.main.loadNibNamed("newsDetails", owner: self, options: nil)?.first as! newsDetailsTableViewCell

here newsDetails is xib file name.


V
Vladimir Vodolazkiy

I ran into this message when UITableView in the IB was moved into another subview with Cmd-C - Cmd-V.

All identifiers, delegate methods, links in the IB etc. stay intact, but exception is raised at the runtime.

The only solution is to clear all inks, related to tableview in the IB (outlet, datasource, delegate) and make them again.


A
AE0089

If anyone is doing Unit Testing on a tableView and you're wondering why this error is appearing, just make sure that if you're using a text fixture, you must declare the system under test (SUT) in the setUp function correctly otherwise this error will keep coming up. It is also crucial you call loadViewIfNeeded() so the outlets between your code and storyboard are connected.

override func setUp() {
        super.setUp()
        
        let storyboard = UIStoryboard(name: "Main", bundle: nil)           
        
        sutSearch = storyboard.instantiateViewController(identifier:String(describing: SearchTableViewController.self))
        
        sutSearch.loadViewIfNeeded() // To make sure your outlets are connected.
        
    }

D
Don Muthiani

In the “Subclass of” field, select UITableViewController.

The class title changes to xxxxTableViewController. Leave that as is.

Make sure the “Also create XIB file” option is selected.


t
tommmm

Make sure you have the identifier in the attributes filled out with your cell identifier


A
Amin Lakhani

I was also struggling with the same problem. I had actually deleted the class and rebuilt it. Someone, the storyboard had dropped the link between prototype cell and the identifier.

I deleted the identifier name and re-typed the identifier name again.

It worked.


K
Kuringan

If the classic solutions (register identifier for class in code or IB) do not work: try to relaunch Xcode, turns out my storyboard stopped saving edits I was made, including setting the reuse identifier.


p
pkamb

My dynamic tableview was working properly, with cell identifier set on the Storyboard and in dequeueReusableCell(withIdentifier:.

I then switched the UITableView content from Dynamic Prototypes to Static Cells.

Running the app immediately caused the error, although the cell's identifier was still set to the same value on the Storyboard.

For a static table view, you must register the cell identifier outside the Storyboard:

tableView.register(EntryNutritionCell.self, forCellReuseIdentifier: "Cell")

or, comment out or remove cellForRowAtIndexPath: entirely. This function isn't really used by the Static table view, but is still called(?) and causes the crash:

//    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
//        return cell
//    }

P
Pablo

'Table View Cell' identifier must match the class identifier.

ex: if your 'Table View Cell' identifier is named "myCellId", then your code should be:

let myCell = tableView.dequeueReusableCell(withIdentifier: "myCellId", for: indexPath).

Also, after hours of troubleshooting i realized that having a GestureRecognizer class in my didLoad() was not allowing me to click table cells. so removing all 'hide keyboard' functionality from didLoad() and other extra code solved it for me.