dismissViewControllerAnimated causes EXC_BAD_ACCESS - swift

einarnot picture einarnot · Jun 16, 2014 · Viewed 7.8k times · Source

Im trying to dismiss a UIViewController with dismissViewControllerAnimated(true, completion: {}) but I get a EXC_BAD_ACCESS when trying to do it. (that is, in 1 out of 10 times its working).

I have used a custom transitionDelegate, and when Im not setting that, its working.

The ListTransitionDelegate returns animators and presentationController.

The PresentationController looks like this

    init(presentingViewController: UIViewController!, presentedViewController: UIViewController!, controllerStyle: SideControllerStyle, shortest: CGFloat) {
    self.controllerStyle = controllerStyle
    self.shortest = shortest

    super.init(presentingViewController: presentingViewController, presentedViewController: presentedViewController)

    self.dimmingView.backgroundColor = UIColor.blackColor()

    var tapGesture = UITapGestureRecognizer(target: self, action: Selector("closePresented"))
    dimmingView.addGestureRecognizer(tapGesture)
}

override func adaptivePresentationStyle() -> UIModalPresentationStyle
{
    return UIModalPresentationStyle.OverFullScreen
}

override func shouldPresentInFullscreen() -> Bool
{
    return true
}

override func presentationTransitionWillBegin() {
    var containerView = self.containerView
    self.dimmingView.frame = self.containerView.bounds
    containerView.insertSubview(self.dimmingView, atIndex:0)

    presentedViewController.transitionCoordinator().animateAlongsideTransition({context in
        self.dimmingView.alpha = 0.5
        }, completion:nil)
}

override func presentationTransitionDidEnd(completed: Bool)
{
    if !completed {
        self.dimmingView.removeFromSuperview()
    }
}

override func dismissalTransitionDidEnd(completed: Bool)
{
    self.dimmingView.removeFromSuperview()
}

override func dismissalTransitionWillBegin() {
    presentedViewController.transitionCoordinator().animateAlongsideTransition({context in
        self.dimmingView.alpha = 0
        }, completion: nil)
}

func closePresented() {
    var presenting = self.presentingViewController

   presentedViewController.dismissViewControllerAnimated(true, completion: nil)
}

override func sizeForChildContentContainer(container: UIContentContainer!, withParentContainerSize parentSize: CGSize) -> CGSize {
    var size : CGSize

    switch self.controllerStyle {
    case .Left, .Right:
        size = CGSizeMake(self.shortest, parentSize.height)

    case .Bottom, .Top:
        size = CGSizeMake(parentSize.width, self.shortest)

    default:
        size = CGSizeMake(parentSize.width, parentSize.height)
    }

    return size
}

override func frameOfPresentedViewInContainerView() -> CGRect {
    var frame : CGRect
    var size = sizeForChildContentContainer(nil, withParentContainerSize: containerView.bounds.size)

    switch self.controllerStyle {
    case .Left:
        frame = CGRectMake(containerView.bounds.size.width - size.width, 0, size.width, size.height)

    case .Right:
        frame = CGRectMake(0, 0, size.width, size.height)

    case .Bottom:
        frame = CGRectMake(0, containerView.bounds.size.height - size.height, size.width, size.height)

    case .Top:
        frame = CGRectMake(0, 0, size.width, size.height)

    default:
        frame = CGRectMake(0, 0, size.width, size.height)
    }
    return frame
}

Answer

Andrew picture Andrew · Aug 2, 2014

Try enabling zombie objects in your scheme settings. (Remember to turn it off when you're done because that change won't show up in your source control and you really don't want to release an app without ARC!)

If you get the error message

-[_UILayoutGuide superview]: message sent to deallocated instance 0x1781ac6a0

then just add this code to the view controller being dismissed:

deinit {
    self.view.removeFromSuperview()
}

UILayoutGuide is a private autolayout class. I believe this to be a bug (and filed it as such), since why would a dismissed view controller have any need for autolayout? Removing a class from its superview will preemptively prevent the autolayout constraints from being accessed after they've been deallocated.