What I usually do in this case is to create an enum representing the type of rows that I want to display.
For example, if we want to create a To-Do List View Controller, in which we want to display two static cells: (1) "Welcome to To-Do App!" cell, (2) "Please enter your task" cell; and dynamic cells containing the to-do items, we can create an enum as follows:
enum ToDoSectionType {
case welcome // for static cell
case instruction // for static cell
case tasks([Task]) // for dynamic cell
var numberOfRows: Int {
switch self {
case .welcome: return 1
case .instruction: return 1
case let .tasks(tasks): return tasks.count
}
}
}
We can create a stored property in the TableView class, like
var sectionsType: [ToDoSectionType]
and assign it the correct value once we already loaded the tasks
let tasks = loadTasks()
sectionsType = [.welcome, .instruction, .tasks(tasks)]
Then in the TableViewDataSource methods, we can implement the numberOfRowsInSection and cellForRowAtIndexPath methods, like
func numberOfSections(in: UITableView) -> Int {
return sectionsType.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let sectionType = sectionsType[section]
return sectionType.numberOfRows
}
func tableView(_ tableView: UITableView, cellForRowAtIndexPath indexPath: IndexPath) -> UITableViewCell {
let sectionType = sectionsType[indexPath.section]
switch sectionType {
case .welcome:
let cell = tableView.dequeueReusableCell(withIdentifier: "WelcomeStaticCell")!
return cell
case .instruction:
let cell = tableView.dequeueReusableCell(withIdentifier: "InstructionStaticCell")!
return cell
case let .tasks(tasks):
let cell = tableView.dequeueReusableCell(withIdentifier: "DynamicTaskCell")!
let task = tasks[indexPath.row]
cell.textLabel?.text = task.name
return cell
}
}
That way, we can have a combination of static and dynamic data using only one UITableView.