Search code examples
swiftuitableviewinterface-builderpopover

How to access parent view controller from popover in swift, using storyboard


Pushing a UIButton in a UIViewController (detailview of a splitviewcontroller) opens a UITableViewController, presented as a popover. This is accomplished by a segue, and "kind" is set as "Present as Popover" in attributes inspector. When a UITableViewCell in the UITableViewController is selected, I want the UIViewController to catch this selection.

This is what I am trying to do in the UITableViewController:

 override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

        let cell = tableView.cellForRowAtIndexPath(indexPath)
        let myViewController = presentingViewController as! MyViewController

        myViewController.variable = cell.someProperty
        self.dismissViewControllerAnimated(true, completion: nil)
    }

This gives in the log: "fatal error: unexpectedly found nil while unwrapping an Optional value", indicating that I fail to catch the parentview/presentingview. After reading about popovers, I feel I should implement a delegate and delegate methods somwhere. But I fail to undersetand how.

What is the correct way to do this?


Solution

  • You probably want to use the delegation design pattern. If I understand your situation correctly, you can accomplish that by doing something like:

    class MyTableViewController: UITableViewController {
        // ...
    
        weak var myViewControllerDelegate: MyViewController? // Make sure it's weak! .. or you know what you're doing, haha
    
        override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
            // ...
            let property = 5 // cell.property
            self.myViewControllerDelegate?.myTableViewController(self, didSelectCellWithProperty: property)
        }
    }
    
    class MyViewController: UIViewController {
        // ...
    
        // In viewDidLoad or elsewhere, if necessary
        override func viewDidLoad() {
            super.viewDidLoad()
            //...
    
            myTableVCInstance.myViewControllerDelegate = self // This will set the delegate we created to self
        }
    
        func myTableViewController(viewController: MyTableViewController, didSelectCellWithProperty property: Int) {
            // ...
        }
    }
    

    Note the naming of myViewControllerDelegate so as not to clash with the delegate that UITableViewController already has, which would be of type UITableControllerDelegate.

    This example is intended to show a point. You would probably want to use a protocol to clean it up.