UIPopoverController Setup In Storyboard Cannot Be Dismissed Programmatically Without Reverting to Deprecated API

Originator:matt.long
Number:rdar://19379992 Date Originated:05-Jan-2015 04:48 PM
Status:Closed Resolved:09-Jun-2015 11:27 AM
Product:iOS Product Version:8.1.2
Classification: Reproducible:100%
 
I have a toolbar with multiple buttons each of which are connected to other view controllers in my storyboard via adaptive popover segue. When I tap a button, the first popover displays. If, however, I tap the second button next to it, it won't automatically dismiss the first popover, so I need to dismiss it programmatically. The problem there, though, is that I cannot typecast the segue to a UIStoryboardPopoverSegue inside of prepareForSegue because the actual type of the segue when running with the debugger is type UIStoryboardPopoverPresentationSegue which is not a concrete type that we (developers) have access to. This code fails at the typecast (I also tried it with the 'if let' syntax):

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if self.popoverController != nil {
        self.popoverController!.dismissPopoverAnimated(true)
    }
    
    if segue.identifier == "Popover1Segue" {
        var popoverSegue = (segue as UIStoryboardPopoverSegue)
        var destination = segue.destinationViewController as PoppedViewController
        
        self.popoverController = popoverSegue.popoverController
    }
}

If I change the segue type in the storyboard to use the deprecated popover segue, rather than the adaptive one, it works fine.

Steps to Reproduce:
1. Create a basic iPad app
2. Add a toolbar to the main view and add two buttons to it
3. Add two view controllers to the storyboard and drag a connection from button one to one of them and from button two to the other
4. Implement prepareForSegue in the main view controller using the following code:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if self.popoverController != nil {
        self.popoverController!.dismissPopoverAnimated(true)
    }
    
    if segue.identifier == "Popover1Segue" {
        var popoverSegue = (segue as UIStoryboardPopoverSegue)
        var destination = segue.destinationViewController as PoppedViewController
        
        self.popoverController = popoverSegue.popoverController
    }
}

5. Place a breakpoint on the line where the typecast to UIStoryboardPopoverSegue is happening. 
6. Run to the breakpoint and step over

The app will crash because the typecast fails. I can prevent a crash by using the 'if let' syntax, however, this does not solve the problem of not being able to dismiss the popover programmatically since the typecast is still failing.

Expected Results:
I expect to be able to typecast to a UIStoryboardPopoverSegue or something like it so that I can keep a reference to the UIPopoverController being used so that I can dismiss it later (and not have to refer to a deprecated API to do so)

Actual Results:
I am unable to typecast to a type that is available to developers since the actual type of the segue in prepareForSegue is UIStoryboardPopoverPresentationSegue

Version:
iOS 8.1.2

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!