UITableView Custom Cell not working - ios

My program keeps crashing in the cellForRowAtIndexPath method when I am trying to create a custom table cell. I have put a breakpoint on each line in the code, and the code fails after I try creating the cell variable with the error: unexpectedly found nil while unwrapping optional value. I have used custom table cells successfully many times before and have not run into this issue. It seems simple but I can't figure out what is wrong. Perhaps something in xcode changed that I'm unaware of? Any help is appreciated. Thanks!... Also, I did in fact register my custom cell in viewDidLoad. I'll include that code as well.
var nib = UINib(nibName: "FeedTableViewCell", bundle: nil)
tableView.registerNib(nib, forCellReuseIdentifier: "feedCell")
Probem Code Below:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:FeedTableViewCell = tableView.dequeueReusableCellWithIdentifier("feedCell", forIndexPath: indexPath) as! FeedTableViewCell
cell.descriptionLabel.text = "Testing the description label of my cell."
return cell
}
Update
The one difference between this project and others that have worked is that Xcode is now prompting me to put a bang (!) after as, whereas before I never used one. If I don't add (!) it gives me the error message "AnyObject is not convertible to FeedTableViewCell"
as! FeedTableViewCell -instead of- as FeedTableViewCell
FeedTableViewCell Class
import UIKit
class FeedTableViewCell: UITableViewCell {
#IBOutlet weak var descriptionLabel: UILabel!
#IBOutlet weak var priceLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
priceLabel.font = UIFont(name: "AvenirNext-Bold", size: 30.0)
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}

After spending way too much time trying to get it to work. I nuked my custom table cell, created a brand new one, set it up the exact same way, and everything is working fine now. Still have no idea what happened, but I guess the lesson from this is that sometimes you just have to nuke it and start over.

you should used like this
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("feedCell", forIndexPath: indexPath) as FeedTableViewCell
cell.descriptionLabel.text = "Testing the description label of my cell."
return cell
}
for more help used this link http://shrikar.com/blog/2015/01/17/uitableview-and-uitableviewcell-customization-in-swift/

You should use
var cell:FeedTableViewCell = tableView.dequeueReusableCellWithIdentifier("feedCell",) as! FeedTableViewCell
NSIndexPath may make this issue.
HTH, Enjoy Coding !!

Related

implicitly unwrapping an Optional value on custom cell of table view

first of all i'm saying straight forward I know this is "duplicate" and and this is my 2nd time asking the same question - the problem is that my first one has been closed without me understanding the problem so please if someone wants to close this question again first let me understand what am I doing wrong. The solution I got last time was not relevant so if I could get addressed specifically that would be great!
I am trying to create a custom cell on tableview from an array. when I append any filed on my custom cell I get unexpected nil on all of the fileds and I have no idea why
this is my custom cell:
class CustomMovieCell: UITableViewCell {
#IBOutlet weak var title: UILabel!
#IBOutlet weak var rating: UILabel!
#IBOutlet weak var releaseYear: UILabel!
#IBOutlet weak var genre: UILabel!
var imageBackground: String!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
}
and this is my UITableView cellForRowAtIndexPath method:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MovieCell", for: indexPath) as! CustomMovieCell
let movieFetched = Movie(title: moviesArray[indexPath.row].title, image: moviesArray[indexPath.row].image, rating: moviesArray[indexPath.row].rating, releaseYear: moviesArray[indexPath.row].releaseYear, genre: moviesArray[indexPath.row].genre)
print(movieFetched)
cell.title.text? = movieFetched.title
cell.rating.text? = String(movieFetched.rating)
cell.releaseYear.text? = String(movieFetched.releaseYear)
cell.genre.text? = String(movieFetched.genre[0])
return cell
}
what am I missing? when appending ANY of the files I get unexpectedly found nil while unwrapping optional value - I did not know UIlabel as IBOutlet are optional? even-though they are not optional in my custom cell class.
when debugging I can see that all values of the cell - title, image, rating, releaseYear and genre are nil when trying to assign them a value - so I really have no idea what to do at this point. I have deleted and re-created the cell from scratch and it did not make any differents.
As I already stated - I know this is "duplicate". please though - do not close it before you help me because I did not get any answer the last time, I got directed to a wall-of-text page that did not help me understand my issue. The other "duplicate" pages are like a general "what are optional values" kind of question and do not help me with this specific issue.
edit:
I have uploaded this project to github if it helps anyone help me to figure out this issue
https://github.com/alonsd/MoviesApi
You've connected the custom cell class with 2 cells. One is in xib and another one is in this UIViewController. This UIViewController's prototype cell doesn't have these labels. So it will be nil and it will crash
Delete the prototype cell from MoviesViewController in storyboard. And add this in MoviesViewController viewDidLoad
tableView.register(UINib(nibName: "TableViewCell", bundle: nil), forCellReuseIdentifier: "MovieCell")
Change tableView cellForRowAt method as follows
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MovieCell") as! TableViewCell
cell.title.text = moviesArray[indexPath.row].title
cell.rating.text = String(moviesArray[indexPath.row].rating)
cell.releaseYear.text = String(moviesArray[indexPath.row].releaseYear)
cell.genre.text = String(moviesArray[indexPath.row].genre[0])
return cell
}

How to use the dequeueReuseableCellwithIdentifier method in the UITableViewCell class?

Usually, We use the dequeueReuseableCellwithIdentifier method in ViewController class but I want to use this method in the UITableViewCell.I have tried but I got the exception like this.
fatal error: unexpectedly found nil while unwrapping an optional value
ViewController Class:
#IBOutlet var tableView: UITableView!
var tableData:[songData] = [songData]()
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.backgroundColor = UIColor.orangeColor()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = TableViewCell()
cell.datas()
return cell
}
}
TableViewCell Class:
#IBOutlet var text1: UILabel!
#IBOutlet var text2: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
func datas(){
let vc = ViewController()
let tableData = vc.tableData
print(tableData)
let tableview = vc.tableView
let indexpath:NSIndexPath = NSIndexPath()
let cell = tableview.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexpath) as! TableViewCell //The fatal error is showing exactly at this line.
let artistAndAlbum = tableData[indexpath.row]
cell.text1.text = artistAndAlbum.country
cell.text2.text = artistAndAlbum.currency
tableview.reloadData()
}
I need to customize my table data in the TableViewCell class.If it is possible help me or else why it is not possible?
You're going about this the wrong way. It honestly doesn't make any sense for your table cell subclass to be creating itself. It does make sense, however, for your cell subclass to be passed data and for it to populate itself from that.
You should have your view controller dequeue the cell as normal and then change your table cell function to take some data as a parameter and update itself.
In your view controller:
override func viewDidLoad() {
super.viewDidLoad()
tableView.registerNib(UINib(nibName: "INSERT_NIB_NAME", bundle: nil), forCellReuseIdentifier: "Cell")
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! TableViewCell
cell.updateWithData(tableData[indexPath.row])
return cell
}
If your cell is a prototype cell in the storyboard then you have to set the reuse identifier there instead of registering in viewDidLoad.
In your table cell:
func updateWithData(artistAndAlbum: songData) {
text1.text = artistAndAlbum.country
text2.text = artistAndAlbum.currency
}
In your view controller's viewDidLoad(), register the class with a reuse identifier.
tableView.registerClass(TableViewCell.self, forCellReuseIdentifier: "ID")
Then your cellForRowAtIndexPath method can dequeue your custom cell.
tableView.dequeueReuseableCellWithIdentifier("ID", indexPath: indexPath)
This isn't just limited to view controllers. If you have a custom table view cell, then register the class for a reuse identifier wherever you setup the table view and then dequeue your custom cell with that identifier in its cellForRowAtIndexPath.
As a general rule of thumb, your view should not keep a reference to its view controller. The view shouldn't care about any view controllers or need to know what the view controller is doing. Either the entire table view and all of its workings should go in your view, hidden from the view controller, or you should keep all of your table view code in the view controller. This will make your life much easier.
Firstly you must set name for cell identifier
after it in cellForRowAtIndexPath method used this code:-
for custom cell
CustomCellTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CELL" forIndexPath:indexPath];
//-------------------------------------------------------------
for normal cell
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CELL" forIndexPath:indexPath];
Check your vc.tableView. It's probably nil

Custom UITableViewCell with nib and Auto Layout

I’m getting pretty sick of Auto Layout with UITableView now…
Apple’s docs and code demos all seem to work for them, but when I try it I get no luck. I’ve even deleted and rebuilt nibs from scratch just to see if I’ve set properties inadvertently… Twice.
Trouble is, this time round I’ve got Auto Layout cells working, woo? No. They only resize when scrolled out of the viewport and back in. (I’m guessing by a reload of some kind).
Has anyone come across this issue? There’s a few questions similar to it on SO but no fixes, just discussions of how it must be a bug.
Here is my code:
Called on the UITableView’s IBOutlet didSet method:
private func loadHeadlinesTableView()
{
headlinesTableView.delegate = self
headlinesTableView.dataSource = self
// Register classes/nibs
headlinesTableView.registerClass(HeadlineHeroTableViewCell.self, forCellReuseIdentifier: CellIdentifiers.HeroHeadline)
headlinesTableView.registerNib(UINib(nibName: "HeadlineHeroTableViewCell", bundle: nil), forCellReuseIdentifier: CellIdentifiers.HeroHeadline)
headlinesTableView.registerClass(HeadlineBigTableViewCell.self, forCellReuseIdentifier: CellIdentifiers.BigHeadline)
headlinesTableView.registerNib(UINib(nibName: "HeadlineBigTableViewCell", bundle: nil), forCellReuseIdentifier: CellIdentifiers.BigHeadline)
headlinesTableView.registerClass(HeadlineMediumTableViewCell.self, forCellReuseIdentifier: CellIdentifiers.MediumHeadline)
headlinesTableView.registerNib(UINib(nibName: "HeadlineMediumTableViewCell", bundle: nil), forCellReuseIdentifier: CellIdentifiers.MediumHeadline)
headlinesTableView.registerClass(HeadlineSmallTableViewCell.self, forCellReuseIdentifier: CellIdentifiers.SmallHeadline)
headlinesTableView.registerNib(UINib(nibName: "HeadlineSmallTableViewCell", bundle: nil), forCellReuseIdentifier: CellIdentifiers.SmallHeadline)
// Automatic cell height
headlinesTableView.rowHeight = UITableViewAutomaticDimension
headlinesTableView.estimatedRowHeight = 128
headlinesTableView.backgroundView = nil
headlinesTableView.backgroundColor = UIColor.clearColor()
}
cellForRowAtIndexPath:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
if tableView.isEqual(headlinesTableView)
{
// Headlines
var cell: HeadlineTableViewCell!
switch indexPath.section
{
case HeadlineSections.Index.HeroHeadlines:
// Hero
cell = tableView.dequeueReusableCellWithIdentifier(CellIdentifiers.HeroHeadline, forIndexPath: indexPath) as? HeadlineHeroTableViewCell
case HeadlineSections.Index.BigHeadlines:
// Big
cell = tableView.dequeueReusableCellWithIdentifier(CellIdentifiers.BigHeadline, forIndexPath: indexPath) as? HeadlineBigTableViewCell
case HeadlineSections.Index.MediumHeadlines:
// Medium
cell = tableView.dequeueReusableCellWithIdentifier(CellIdentifiers.MediumHeadline, forIndexPath: indexPath) as? HeadlineMediumTableViewCell
case HeadlineSections.Index.SmallHeadlines:
// Small
cell = tableView.dequeueReusableCellWithIdentifier(CellIdentifiers.SmallHeadline, forIndexPath: indexPath) as? HeadlineSmallTableViewCell
default:
break
}
// Return cell
return cell
}
return UITableViewCell()
}
willDisplayCell:
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath)
{
if tableView.isEqual(headlinesTableView)
{
// Headlines
let headlineCell = cell as! HeadlineTableViewCell
let headline = headlineForIndexPath(indexPath)
headlineCell.configureWithHeadline(headline)
if let thumbnailURL = headline.thumbnailURL
{
headlineImageForURL(thumbnailURL, completionHandler: { (thumbnail) -> () in
headlineCell.configureWithThumbnail(thumbnail)
})
}
}
}
didEndDisplayingCell:
func tableView(tableView: UITableView, didEndDisplayingCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath)
{
if tableView.isEqual(headlinesTableView)
{
// Headlines
let headline = headlineForIndexPath(indexPath)
if let cacheKey = headline.thumbnailURL?.absoluteString, let downloader = headlineImagesDownloading[cacheKey]
{
downloader.cancelRetreivingThumbnailImage()
headlineImagesDownloading.removeValueForKey(cacheKey)
}
}
}
Custom cell class:
class HeadlineTableViewCell: UITableViewCell
{
// MARK: - Properties
// MARK: Outlets
#IBOutlet private weak var headlineImageView: UIImageView!
#IBOutlet private weak var headlineTitleLabel: UILabel!
#IBOutlet private weak var headlineDescriptionLabel: UILabel!
// MARK: - View Lifecycle
override func awakeFromNib()
{
super.awakeFromNib()
// Initialization code
}
// MARK: - Methods
func configureWithHeadline(headline: Headline?)
{
headlineTitleLabel?.text = headline?.title
headlineDescriptionLabel?.text = headline?.paragraph
}
func configureWithThumbnail(thumbnail: UIImage?)
{
headlineImageView?.image = thumbnail
}
}
Here’s some screenshots of my custom cell nib. It was more advanced but now I’m struggling with just a label…
I know it’s a lot but I really have no idea where I could be going wrong here… Thanks
Okay, so after a ton of work and nearly having to buy AppleCare before “accidentally” dropping my Mac against a wall, it seems any calls to tableView(_:willDisplayCell:forRowAtIndexPath:) whereby you might affect the contents of a cell, i.e like my cell configuration methods, disrupts Auto Layout.
I’m sure I read somewhere that tableView(_:willDisplayCell:forRowAtIndexPath:) is supposed to be used for cell configuration but a closer look at Apple Docs says:
A table view sends this message to its delegate just before it uses cell to draw a row, thereby permitting the delegate to customize the cell object before it is displayed. This method gives the delegate a chance to override state-based properties set earlier by the table view, such as selection and background color. After the delegate returns, the table view sets only the alpha and frame properties, and then only when animating rows as they slide in or out.
“Customise the cell object before it is displayed”, not its contents.
Annoyingly there’s a little confusion as tableView(_:cellForRowAtIndexPath:) doesn’t say you should customise the contents in that method:
The returned UITableViewCell object is frequently one that the application reuses for performance reasons. You should fetch a previously created cell object that is marked for reuse by sending a dequeueReusableCellWithIdentifier: message to tableView. Various attributes of a table cell are set automatically based on whether the cell is a separator and on information the data source provides, such as for accessory views and editing controls.
In the words of Dumbledore, "well that was fun."

Using a cell in another file in Swift

I would like to keep the content of a UITableView cell in a separate file as I do in Objective-c even in my TodayExtension Swift table in order to wire it to the storyboard. Yet when I try to do it, it complaints it cannot find the class of the cell; this is the function I use:
override func tableView(tableView: UITableView,
cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
println(indexPath)
let cell = tableView.dequeueReusableCellWithIdentifier(
TableViewConstants.cellIdentifier,
forIndexPath: indexPath) as! TodayCell
let entry = busCollection[indexPath.row]
cell.bus=entry.bus
cell.destination=entry.destination;
return cell
}
todayCell is the class in another file it reports it cannot find:
import UIKit
class TodayCell: UITableViewCell {
#IBOutlet var bus: UILabel!
#IBOutlet var stopAddress: UILabel!
#IBOutlet var destination: UILabel!
}
Importing the file, even if not needed according the the Swift documentation, moved the error in the import statement.
Programmatically:
override func viewDidLoad() {
super.viewDidLoad()
tableView.registerClass(todayCell.self, forCellReuseIdentifier: "todayCell")
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("todayCell", forIndexPath: indexPath) as! todayCell
// Setup
return cell
}
This should do it.
Storyboard:
If you're using prototypes, then you just have to set the prototype class to todayCell and an identifier. This identifier is used when you're creating the cell in tableView.dequeueReusableCellWithIdentifier()
I found the problem: Xcode forgot to add the new TodayCell file to the list of compile sources when I added it to the project. Once I manually did it everything worked fine - I had a funny horror trip in a list of errors in the MKStoreManager library, but all of them went away upon returning to the last commit.

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)
}
}
}
}
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.
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?
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,
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 :)
y my case i solved this by named it in the "Identifier" property of Table View Cell:
Don't forgot: to declare in your Class: UITableViewDataSource
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as UITableViewCell
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" !)
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
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")
In Swift 3.0, register a class for your UITableViewCell like this :
tableView.register(UINib(nibName: "YourCellXibName", bundle: nil), forCellReuseIdentifier: "Cell")
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.
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()
}
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:
Stupid mistake:
make sure you add register(TableViewCell.self, forCellReuseIdentifier: "Cell") instead of register(TableViewCell.self, forHeaderFooterViewReuseIdentifier: "Cell")
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"
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")
}
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
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")
}
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")
}
}
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.
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.
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.
}
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.
Make sure you have the identifier in the attributes filled out with your cell identifier
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.
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.
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
// }
'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.
I was struggling with the same problem. i have already check my reusableCell Identifier it was same as in my code. I deleted line of my code
"let Cell = tableView.dequeueReusableCell(withIdentifier: "CELL", for: indexPath)"
clean build
and write it again!
It worked.

Resources