MJaap MJaap - 4 months ago 29
iOS Question

Swift: UIPopoverPresentationControllerDelegate delegate becomes nil

My attempts at getting something back from my UIPopoverPresentationController fails even after setting up a protocol and delegate.

I include both the custom delegate (SavingViewControllerDelegate) and UIPopoverPresentationControllerDelegate in my controller that will call the popover. The user will tap a UIBarButton which is calling a function in my controller. In the controller, I open the Popover programmatically:

let storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("PopoverProfileViewController") as! ProfileViewController
vc.modalPresentationStyle = UIModalPresentationStyle.Popover
let popover: UIPopoverPresentationController = vc.popoverPresentationController!
popover.barButtonItem = sender as? UIBarButtonItem
popover.delegate = self
self.presentViewController(vc, animated: true, completion:nil)


in this view controller, I have this function

func sendLoginStatus(status : Bool) {
print("LoginStatus")
print(status)
}


In the popover's view controller, I added a protocol:

protocol SavingViewControllerDelegate
{
func sendLoginStatus(status : Bool)
}


I also added a breakout at func sendLoginStatus(status : Bool), which returns "delegate SavingViewControllerDelegate? Some".

In ProfileViewController:

class ProfileViewController: UIViewController {
var delegate : SavingViewControllerDelegate?


When the user taps a button, a bool value should be send back to the calling controller.

@IBAction func logoutButton(sender: AnyObject) {
print("sendStatus")
delegate?.sendLoginStatus(true)
dismissViewControllerAnimated(true, completion: nil)
}


I added a breakpoint at delegate?.sendLoginStatus(true), which returns that "delegate SavingViewControllerDelegate?" is nil. sendLoginStatus is never called.

Answer

You used a delegate from UIPopoverPresentationController and expected results from your own protocol.

Instead of setting the popover delegate conforming to protocol UIPopoverPresentationControllerDelegate you should create a reference to your own delegate:

let storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("PopoverProfileViewController") as! ProfileViewController

// Setting the SavingViewControllerDelegate
vc.delegate = self
vc.modalPresentationStyle = UIModalPresentationStyle.Popover

let popover: UIPopoverPresentationController = vc.popoverPresentationController!
popover.barButtonItem = sender as? UIBarButtonItem

// Setting the UIPopoverPresentationControllerDelegate
popover.delegate = self

self.presentViewController(vc, animated: true, completion:nil)

You can now use your own delegate functions and the UIPopoverPresentationController delegate functions:

extension YourClass : UIPopoverPresentationControllerDelegate {
    // All functions of the UIPopoverPresentationControllerDelegate you wish to use
}

extension YourClass : SavingViewControllerDelegate {
    func sendLoginStatus(status : Bool) {
        // Code
    }
}

Sidenote 1: to prevent a retain cycle of delegates I'd recommend a weak var delegate: SavingViewControllerDelegate? instead of just var ~~

Sidenote 2: It is common practice to also include a sender in delegate functions:

protocol SavingViewControllerDelegate {
    func sendLoginStatus(sender: ProfileViewController, status : Bool)
}
Comments