I’m using UIKit programmatically. I’ve got a UITableView working fine in another view controller, and I’ve largely copied the code I used there to this VC, and yet I get no errors and the UITableView is not displayed. I checked the Debug View Hierarchy and it isn’t present there either. I’m not sure if this is related, but upon launching the Debug View Hierarchy the following message is displayed repeatedly in the debug window:
[API] Failed to get renderer info (client=0x82b3d507) [0x5 (os/kern) failure]. My print statement inside numberOfRowsInSection does fire, but my print statement in cellForRowAt does not. WorkoutTemplate and its child structs are simple data structures with no logic. I have a static property on WorkoutTemplate that is used for dummy data when laying out the UI.
class CreateWorkoutVC: UIViewController, UITableViewDataSource, UITableViewDelegate {
var exerciseListing: UITableView!
var workoutTemplate: WorkoutTemplate!
init(workoutTemplate: WorkoutTemplate) {
super.init(nibName: nil, bundle: nil)
self.workoutTemplate = workoutTemplate
configure()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
}
private func configure() {
let padding: CGFloat = 20
exerciseListing = UITableView(frame: view.frame)
view.addSubview(exerciseListing)
exerciseListing.register(UITableViewCell.self, forCellReuseIdentifier: "exercise")
exerciseListing.rowHeight = 50
exerciseListing.dataSource = self
exerciseListing.delegate = self
exerciseListing.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
exerciseListing.topAnchor.constraint(equalTo: view.topAnchor, constant: padding),
exerciseListing.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: padding),
exerciseListing.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -padding)
])
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("In numberOfRowsInSection: \(workoutTemplate.exerciseSets.count)")
return workoutTemplate.exerciseSets.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "exercise", for: indexPath)
let cellLabel = getCellLabel(withText: workoutTemplate.exerciseSets[indexPath.row].exercise.exerciseName)
print(workoutTemplate.exerciseSets[indexPath.row].exercise.exerciseName)
cell.addSubview(cellLabel)
let padding: CGFloat = 8
NSLayoutConstraint.activate([
cellLabel.centerYAnchor.constraint(equalTo: cell.centerYAnchor),
cellLabel.leadingAnchor.constraint(equalTo: cell.leadingAnchor, constant: padding),
cellLabel.trailingAnchor.constraint(equalTo: cell.trailingAnchor, constant: -padding),
cellLabel.heightAnchor.constraint(equalTo: cell.heightAnchor)
])
cell.backgroundColor = .secondarySystemBackground
return cell
}
func getCellLabel(withText labelText: String) -> UILabel {
let cellLabel = UILabel(frame: .zero)
cellLabel.text = labelText
cellLabel.textColor = .label
cellLabel.adjustsFontSizeToFitWidth = true
cellLabel.minimumScaleFactor = 0.90
cellLabel.lineBreakMode = .byTruncatingTail
cellLabel.translatesAutoresizingMaskIntoConstraints = false
cellLabel.textAlignment = .left
cellLabel.font = UIFont.systemFont(ofSize: 16, weight: .bold)
return cellLabel
}
}
Data Structures:
struct WorkoutTemplate {
let workoutName: String
var exerciseSets: [ExerciseSet]
mutating func addExerciseSet(exerciseSet: ExerciseSet) {
exerciseSets.append(exerciseSet)
}
static let exampleWorkouts = [WorkoutTemplate(workoutName: "Upper Body 1", exerciseSets: [ExerciseSet(exercise: Exercise(exerciseId: UUID(), exerciseName: "Bench Press"), sets: 3, targetReps: 8, targetRPE: 8, restPeriod: 2), ExerciseSet(exercise: Exercise(exerciseId: UUID(), exerciseName: "T-Bar Row"), sets: 3, targetReps: 8, targetRPE: 8, restPeriod: 3)]), WorkoutTemplate(workoutName: "Lower Body 1", exerciseSets: [ExerciseSet(exercise: Exercise(exerciseId: UUID(), exerciseName: "Hack Squats"), sets: 3, targetReps: 8, targetRPE: 8, restPeriod: 2), ExerciseSet(exercise: Exercise(exerciseId: UUID(), exerciseName: "Leg Ext"), sets: 3, targetReps: 8, targetRPE: 8, restPeriod: 3)])]
}
struct ExerciseSet {
let exercise: Exercise
let sets: Int
let targetReps: Int
let targetRPE: Int
let restPeriod: Int
}
struct Exercise {
let exerciseId: UUID
let exerciseName: String
}
>Solution :
You said:
I checked the Debug View Hierarchy and it isn’t present there either.
You checked in the graphical representation? Or in the hierarchy in the panel on the left? I ask because you do not appear to ever set the bottom constraint, so its height could be anything (even zero). And that would cause numberOfRowsInSection to be called, but cellForRowAt not to be called.
Bottom line, the table view was zero height, you wouldn’t see it in that wireframe (or it would appear to be a horizontal line). That’s why I advise navigating through the view hierarchy in the panel on the left, to find the tableview. The wireframe is great at debugging placement of views that you can see, but zero height views are harder to analyzer in there.