2

Let's say I have an app that displays details for a person. Each person can have zero or more phone numbers and zero or more notes attached to it. Thus, I have a Core Data entity Person with one-to-many relationships to the Phone entity and the Note entity. I want to show these in a UITableView, where there is one section "phones" and one section "notes".

So, numberOfRowsInSection would look like that:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
 switch section {
 case 0: // Phones
 if self.person.phones.count > 0 {
 return self.person.phones.count
 } else {
 return 1 // We want a different cell to display "no phones"
 }
 case 1: // Notes
 if self.person.notes.count > 0 {
 return self.person.notes.count
 } else {
 return 1 // We want a different cell to display "no notes"
 default:
 return 0
 }
}

And cellForRowAt would look like this:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
 switch indexPath.section {
 case 0:
 if self.person.phones.count > 0 {
 return UITableViewCell.init(style: .default, reuseIdentifier: "PhoneNumberCell")
 } else {
 return UITableViewCell.init(style: .default, reuseIdentifier: "NoPhoneNumbersCell")
 }
 case 1:
 if self.person.notes.count > 0 {
 return UITableViewCell.init(style: .default, reuseIdentifier: "NoteCell")
 } else {
 return UITableViewCell.init(style: .default, reuseIdentifier: "NoNotesCell")
 }
 default:
 return UITableViewCell.init(style: .default, reuseIdentifier: "default")
 }
}

And then, you can guess already, the same code would repeat for willDisplay:

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
 switch indexPath.section {
 case 0:
 if self.person.phones.count > 0 {
 // Configure Phone Cell
 } else {
 // Configure No Phones Cell
 }
 case 1:
 if self.person.notes.count > 0 {
 // Configure Note Cell
 } else {
 // Configure No Notes Cell
 }
 default: break
 }
}

Same would apply for didSelectRowAt (and other delegate/datasource methods) but I won't copy more here.

What I want to do is get rid of this long and repeating switch with if..else statement but the problem is that in some cases I use it to return a number, in others a String and in others to just configure a cell.

Does anyone have an idea or pattern to recommend for this case?

asked Oct 11, 2016 at 16:00
3

1 Answer 1

1

Here's the kind of data source I would like to see for your example:

func numberOfSections(in tableView: UITableView) -> Int {
 return sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
 return sections[section].itemCount
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
 return sections[indexPath.section].cell(forRow: indexPath.row)
}

To make the above work, you will need a Section Protocol:

protocol Section {
 var itemCount: Int { get }
 var cell(forRow row: Int) -> UITableViewCell 
}

... as well as a PhoneNumberSection and NoteSection that both implement that protocol.

answered May 8, 2017 at 1:21
1
  • This is essentially what @amon was suggesting in his comment. Commented May 8, 2017 at 1:24

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.