I'm a bit of a newbie and I may be out of my depth here, but I am running into an issue that I can't seem to crack.
I have a prototype tableview cell in which I am using an array to show an image (UIImage) and a description (UILabel) for each row. I would like each row to be clickable to present a different viewController with an identifier based on the image name (taken from the array).
Everything seems to be working correctly, when I click the specific row it is pointing to the correct ViewController, but I am getting this error:
Attempt to present <Park_Professor.HelpScrollViewController: 0x107011a00> on <Park_Professor.TutorialsTableView: 0x1035163f0> (from <Park_Professor.TutorialsTableView: 0x1035163f0>) whose view is not in the window hierarchy.
Here is my code:
class TutorialsViewController: UIViewController, UIScrollViewDelegate {
let tutorialsClassRef = TutorialsTableView()
@IBOutlet weak var tutorialsTable:TableViewAdjustedHeight! {
didSet {
self.tutorialsTable.delegate = tutorialsClassRef
self.tutorialsTable.dataSource = tutorialsClassRef
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
class TutorialsTableView: UIViewController, UITableViewDataSource, UITableViewDelegate {
struct Tutorials {
let name: String
let description: String
}
let data: [Tutorials] = [
Tutorials(name: "ParkProfessorHelp", description: "Park Professor Features"),
Tutorials(name: "LightningLane", description: "Booking and Modifying Lightning Lane Reservations"),
Tutorials(name: "MobileOrder", description: "Guide to Mobile Ordering Food"),
Tutorials(name: "Parking", description: "Parking Tips")
]
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return data.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let tutorials = data[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "tutorialstableCell", for: indexPath) as! tutorialstableCell
cell.tutorialsImage.image = UIImage(named: tutorials.name + ".png")
cell.tutorialsLabel.text = tutorials.description
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let tutorials = data[indexPath.row]
let mainStoryboard = UIStoryboard(name: "Main", bundle: Bundle.main)
let popupVC = mainStoryboard.instantiateViewController(withIdentifier: tutorials.name)
popupVC.modalPresentationStyle = .popover
present(popupVC, animated: true, completion: nil)
}
}
class tutorialstableCell:UITableViewCell {
@IBOutlet weak var tutorialsImage: UIImageView!
@IBOutlet weak var tutorialsLabel: UILabel!
}
}
Based on research I've done it seems like my issue is maybe one of timing... a viewDidLoad vs viewDidAppear issue, but for the life of me I can't figure out how to solve it.
You're calling present()
from a view controller (TutorialsTableView: UIViewController
) that’s not actually on screen.
Just pass a real UIViewController
:
class TutorialsTableView: NSObject, UITableViewDataSource, UITableViewDelegate {
weak var viewController: UIViewController? // !NEW LINE!
class TutorialsViewController: UIViewController, UIScrollViewDelegate {
let tutorialsClassRef = TutorialsTableView()
@IBOutlet weak var tutorialsTable:TableViewAdjustedHeight! {
didSet {
self.tutorialsTable.delegate = tutorialsClassRef
self.tutorialsTable.dataSource = tutorialsClassRef
self.tutorialsTable.viewController = self // !NEW LINE!
}
}
And call present
on that viewController
property:
let popupVC = mainStoryboard.instantiateViewController(withIdentifier: tutorials.name)
popupVC.modalPresentationStyle = .popover
viewController?.present(popupVC, animated: true, completion: nil) // changed code
Also, you might notice I changed TutorialsTableView
from a UIViewController
to NSObject
. Why?
Because this class is only used to separate out the table’s data source and delegate logic — it’s not meant to be shown on screen. We're just keeping things clean and modular.
As for NSObject
, it's required since UIKit protocols like UITableViewDataSource
and UITableViewDelegate
inherit from NSObjectProtocol
. So any class conforming to them needs to inherit from NSObject
.