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?

200_success
145k22 gold badges190 silver badges478 bronze badges
asked Nov 28, 2017 at 18:07
\$\endgroup\$

2 Answers 2

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
}
answered Dec 1, 2017 at 21:14
\$\endgroup\$
2
  • \$\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\$ Commented Dec 2, 2017 at 5:51
  • \$\begingroup\$ Also don't switch on case 0,1 name your constants: CoverSection, StorySection \$\endgroup\$ Commented Jun 5, 2018 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.

answered Dec 1, 2017 at 9:54
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.