1
\$\begingroup\$

Using swift for iOS, here is my cellforRow method

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {   
    switch indexPath.section {
    case 0: // Cover Image
        guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifierCover) as? AddBlogCoverTableViewCell else { return UITableViewCell() }
        cell.layer.backgroundColor = UIColor.clear.cgColor
        cell.selectionStyle = .none
        cell.indexPath = indexPath
        cell.delegate = self
        cell.titleTextField.delegate = self
        cell.coverImageView.image = coverImage
        cell.titleTextField.placeholder = "Title"
        cell.titleTextField?.text = articleName ?? ""
        cell.setBorder(of: 0.7, ofColor: UIColor.lightGray.cgColor)

        return cell

    case 1: // rest story
        guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier) as? AddBlogTableViewCell else { return UITableViewCell() }
        cell.layer.backgroundColor = UIColor.clear.cgColor
        cell.selectionStyle = .none
        cell.indexPath = indexPath
        cell.delegate = self
        cell.captionTextView.delegate = self
        cell.captionTextView.tag = indexPath.row
        cell.tag = indexPath.section
        cell.media = cards?[indexPath.row].media
        cell.captionTextView.text = cards?[indexPath.row].caption ?? ""
        showLocationSuggestions(at: indexPath, in: cell)
        cell.poi = cards?[indexPath.row].poi
        return cell
    default:
        return UITableViewCell()
    }
    return UITableViewCell()
}

How should I avoid repeating the code that I have to provide to the cell in all cases of switch?

\$\endgroup\$
2
\$\begingroup\$

Defensive programming (never force unwrap, no forced cast, ...) is good and important to handle "runtime problems" gracefully: Unexpected user input, failed network connections, I/O errors, and many more.

But programming errors are a different category. Example 1: If

tableView.dequeueReusableCell(withIdentifier: cellIdentifierCover)

fails, or does not return a AddBlogCoverTableViewCell, then you did not configure the table view correctly in the Storyboard. Such cases should be detected during development. Therefore it is better to abort with a runtime error instead of "hiding" the problem and returning a plain UITableViewCell. This is a valid use-case for a forced cast:

 let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifierCover) as! AddBlogCoverTableViewCell

or better:

let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifierCover, for: indexPath) as! AddBlogCoverTableViewCell

Example 2: Your table view has 2 sections, so indexPath.section must be 0 or 1, every other value would be a programming error. Again, fail early instead of hiding the problem:

switch indexPath.section {
case 0:
    // do something ...
case 1:
    // do something ...
default:
    fatalError("Unexpected section \(indexPath.section)")
}

Note also that your final

return UITableViewCell()

is never be executed.


Now for possible simplifications. Both cell classes have some properties in common, these can be defined in a common superclass:

class AddBlogCommonCell : UITableViewCell {
    var indexPath: IndexPath!
    var delegate: UITableViewController!
    // ...
}

class AddBlogCoverTableViewCell : AddBlogCommonCell {
    // ...
}

class AddBlogTableViewCell : AddBlogCommonCell {
    // ...
}

Then you can configure the specific properties inside the switch statement, and the shared properties outside the switch statement, thereby avoiding the code repetition:

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

    let cell: AddBlogCommonCell
    switch indexPath.section {
    case 0:
        let coverCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifierCover) as! AddBlogCoverTableViewCell
        coverCell.titleTextField.delegate = self
        coverCell.coverImageView.image = coverImage
        // ...
        cell = coverCell
    case 1:
        let storyCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier) as! AddBlogTableViewCell
        storyCell.captionTextView.delegate = self
        storyCell.captionTextView.tag = indexPath.row
        // ...
        cell = storyCell
    default:
        fatalError("Unexpected section \(indexPath.section)")
    }

    // AddBlogCommonCell properties:
    cell.delegate = self
    cell.indexPath = indexPath
    // ...

    // UITableViewCell properties:
    cell.layer.backgroundColor = UIColor.clear.cgColor
    cell.selectionStyle = .none
    // ...

    return cell
}
\$\endgroup\$
  • \$\begingroup\$ Thanks a lot for the detailed answer. It's very helpful. But I am using xib, and its a bit tricky to subclass cells using xib. \$\endgroup\$ – sasquatch Dec 2 '17 at 5:51
  • \$\begingroup\$ Also don't switch on case 0,1 name your constants: CoverSection, StorySection \$\endgroup\$ – trapper Jun 5 '18 at 8:02
0
\$\begingroup\$

The easiest and the fastest way that I see is to use a configuration closure.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let configureCell = { (cell: MyGenericTableViewCell) in
        // Generic configurartion
    }
    switch indexPath.section {
    case 0: // Cover Image
        guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifierCover) as? AddBlogCoverTableViewCell else { return UITableViewCell() }
        configureCell(cell)

        // Perform cell-specific config

        return cell

    case 1: // rest story
        guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier) as? AddBlogTableViewCell else { return UITableViewCell() }
  configureCell(cell)

        // Perform cell-specific config

        return cell
    default:
        return UITableViewCell()
    }
    return UITableViewCell()
}

Also, some part of your configuration, such as:

cell.layer.backgroundColor = UIColor.clear.cgColor
cell.selectionStyle = .none

can be put inside initialization methods of the cells.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.