Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Set UITableViewCellStyleSubtitle and dequeueReusableCell in Swift?

I'd like a UITableView with subtitle-style cells that use dequeueReusableCellWithIdentifier.

My original Objective-C code was:

static NSString *reuseIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
if(!cell)
{
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:reuseIdentifier];
}

After searching the few UITableView questions here already on SO, I thought to write it in Swift like so:

tableView.registerClass(UITableViewCell.classForCoder(), forCellReuseIdentifier: "Cell")

let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell

But that doesn't let me say I want a subtitle style. So I tried this:

var cell :UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "Cell")

Which gives me a subtitle cell, but it doesn't let me dequeueReusableCellWithIdentifier.

I've researched some more and looked at this video tutorial, but he creates a separate subclass of UITableViewCell which I assume is unnecessary as I accomplished this same effect previously in Obj-C.

Any ideas? Thanks.

like image 919
WunDaii Avatar asked Jun 05 '14 14:06

WunDaii


People also ask

What is dequeueReusableCell in Swift?

dequeueReusableCell(withIdentifier:)Returns a reusable table-view cell object after locating it by its identifier.

How do I add a prototype cell to UITableView?

Choose iOS -> Source -> Cocoa Touch Class. Name the class TableCiewController and make it a subclass of UITableViewController. Go to the TableViewController. swift file and declare the following array.


3 Answers

Keep in mind that UITableView is defined as an optional in the function, which means your initial cell declaration needs to check for the optional in the property. Also, the returned queued cell is also optional, so ensure you make an optional cast to UITableViewCell. Afterwards, we can force unwrap because we know we have a cell.

var cell:UITableViewCell? =  tableView?.dequeueReusableCellWithIdentifier(reuseIdentifier) as? UITableViewCell if (cell == nil) {    cell = UITableViewCell(style: UITableViewCellStyle.Subtitle,                  reuseIdentifier: reuseIdentifier) } // At this point, we definitely have a cell -- either dequeued or newly created, // so let's force unwrap the optional into a UITableViewCell cell!.detailTextLabel.text = "some text"  return cell 
like image 55
memmons Avatar answered Oct 05 '22 14:10

memmons


If you'd rather avoid optionality, you can make a subclass of UITableViewCell that looks something like this:

class SubtitleTableViewCell: UITableViewCell {      override init(style: UITableViewCellStyle, reuseIdentifier: String?) {         super.init(style: .subtitle, reuseIdentifier: reuseIdentifier)     }      required init?(coder aDecoder: NSCoder) {         fatalError("init(coder:) has not been implemented")     } } 

Then register it using:

override func viewDidLoad() {     super.viewDidLoad()     self.tableView.register(SubtitleTableViewCell.self, forCellReuseIdentifier: reuseIdentifier) } 

This allows your cell customization code to be really nice:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {      let cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier, for: indexPath)      cell.textLabel?.text = "foo"     cell.detailTextLabel?.text = "bar"      return cell } 
like image 30
Jeremy Massel Avatar answered Oct 05 '22 15:10

Jeremy Massel


Basically the same as other answers, but I get around dealing with nasty optionals (you can't return nil from -tableView:cellForRow:atIndexPath: in Swift) by using a computed variable:

Swift 3

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

    let cell: UITableViewCell = {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell") else {
            // Never fails:
            return UITableViewCell(style: UITableViewCellStyle.value1, reuseIdentifier: "UITableViewCell")
        }
        return cell
    }()

    // (cell is non-optional; no need to use ?. or !)

    // Configure your cell:
    cell.textLabel?.text       = "Key"
    cell.detailTextLabel?.text = "Value"

    return cell
}

Edit:

Actually, it would be better to dequeue the cell using: tableView.dequeueReusableCell(withIdentifier:for:) instead.

This later variant of the function automatically instantiates a new cell if no one is available for reusing (exactly what my code does explicitly above), and therefore never returns nil.

like image 24
Nicolas Miari Avatar answered Oct 05 '22 15:10

Nicolas Miari