Jim
Jim

Reputation: 1460

Why do I get a runtime error with using tableView.dequeueReusableCellWithIdentifier

I'm learning about basic Table Views in Swift and running into a problem when I try to use tableView.dequeueResuableCellWithIdentifier.

I had it working by creating a new UITableViewCell each time this method was called (e.g. var cell = UITableViewCell() ) but I know that's very inefficient and not best practice. Now, with the code I've pasted below, I get a runtime error at 'var cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! UITableViewCell'.

I have specified one Prototype cell and given it a reuse identifier of 'cell'.

class ViewController: UIViewController, UITableViewDataSource {

let devCourses = [
    ("iOS App Dev with Swift Essential Training","Simon Allardice"),
    ("iOS 8 SDK New Features","Lee Brimelow"),
    ("Data Visualization with D3.js","Ray Villalobos"),
    ("Swift Essential Training","Simon Allardice"),
    ("Up and Running with AngularJS","Ray Villalobos"),
    ("MySQL Essential Training","Bill Weinman"),
    ("Building Adaptive Android Apps with Fragments","David Gassner"),
    ("Advanced Unity 3D Game Programming","Michael House"),
    ("Up and Running with Ubuntu Desktop Linux","Scott Simpson"),
    ("Up and Running with C","Dan Gookin") ]

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

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

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    var cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! UITableViewCell

    let (courseTitle, courseAuthor) = devCourses[indexPath.row]

    cell.textLabel?.text = courseTitle
    return cell
}

The only output I get is (lldb) so I have no idea what the problem is. I'm using Xcode 6.3.2.

Thanks!

Upvotes: 2

Views: 256

Answers (4)

Jim
Jim

Reputation: 1460

Thank you all for your answers. It turns out I did something stupid - I had accidentally added a breakpoint at that line. EmilioPelaez suggested that might be the problem and sure enough it was. The code is now working as expected.

Thanks again!

Upvotes: 0

vacawama
vacawama

Reputation: 154603

I am able to make your code work with no changes. The key is in the proper setup of the Storyboard.

  1. Make sure the class of the ViewController in your Storyboard is set in the Identity Inspector to ViewController. Note, not UIViewController.

    set Class

  2. Make sure the tableView dataSource has been set. You can control-drag from the tableView in your Storyboard to the ViewController icon at the top and pick dataSource from the pop-up.

    drag from tableView

    choose dataSource

  3. Make sure the prototype cell has the reuse identifier set to "cell".

    enter image description here

Upvotes: 0

tacos_tacos_tacos
tacos_tacos_tacos

Reputation: 10585

If you want to be sure that something else in Storyboards isn't overriding the registration, try this:

override func viewDidLoad() {
    super.viewDidLoad()

    // Make sure that "cell" is the name of the reuse identifier. Maybe use a const in M file to set it.
    let nibName = UINib(nibName: "YourNibName", bundle:nil)
    self.tableView.registerNib(nibName, forCellReuseIdentifier: "cell")
}

Since the viewDidLoad happens after the nib gets loaded, this will ensure that whatever is causing the trouble, you get the last word - unless it is something in your code elsewhere.

struct UIConstants {
    struct SomeViewControllerUIConstants {
        static let cellNibName          = "SpecialCell";
        static let cellReuseIdentifier  = "cell";
    }
}

Also, maybe consider declaring a pseudo-const struct as above. This will reduce the chance of a spelling or capitalization issue causing this sort of runtime exception, which by the way, I think Apple might as well spend the couple of hours to program to handle more gracefully. Why not do case-insensitive search, or string distance case insensitive to see if it can find exactly one match a distance of 0 or 1 away? Anyway, I digress.

Upvotes: 0

BHendricks
BHendricks

Reputation: 4493

If you are using a standard cell, which it seems like you are, you still need to register the class as the cell class to dequeue. Right now, you're tableView doesn't know what type to dequeue.

In viewDidLoad of this method, you should do something like this:

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

This way, the table view will properly dequeue cells of identifier "cell" for this table.

Upvotes: 0

Related Questions