Basti
Basti

Reputation: 256

Attempt to present UIViewController while a presentation is in progress!-Warning

Assume a new iOS project, just with a navigation controller (correctly wired as entry point) and an overridden viewDidAppear() containing the following three lines of code:

            self.presentViewController(UIViewController(), animated: true, completion: nil)
            self.dismissViewControllerAnimated(true, completion: {})
            self.presentViewController(UIViewController(), animated: true, completion: nil)

When executed, that code will raise a warning "Attempt to present UIViewController while a presentation is in progress!" when attempting to present the second controller.

Question: What exactly am I missing in order to dismiss the controller correctly before calling another controller?

Upvotes: 3

Views: 8321

Answers (2)

Rory McKinnel
Rory McKinnel

Reputation: 8014

Assuming you want the main controller to appear, present a controller, dismiss the controller, present again and dismiss then you need to chain the actions so they happen in order.

To prevent it spinning forever, you also need to only run the code when the main controller appears for the first time.

I'm no swift coder, but something like the following should work. There is a check to make sure the controller is being presented or being pushed on and then it runs the sequence using each operations completion to start the next. This guard should make sure that following each dismiss when viewDidAppear gets called that it does not do anything on those occasions.

var firstTime = true;

func presentThenDismiss(finalCompletion: (() -> Void)?)
{
    presentViewController(UIViewController(), animated: true, completion : { [weak self] Void in
        // On completion of the present, we dismiss it
        dispatch_async(dispatch_get_main_queue(), {
            self?.dismissViewControllerAnimated(true, completion: { Void in
                // On completion of the dismiss, we present another
                finalCompletion!()
            })
        })
    })
}

override func viewDidLoad() {
    super.viewDidLoad()


    // We only run the modal presentation code when being presented or
    // being pushed on, NOT when exposed by a model dismiss or pop
    //
    if (firstTime){
        firstTime = false;

        self.presentThenDismiss { () -> Void in
            self.presentThenDismiss { () -> Void in
            }
        }
    }
}

Upvotes: 1

Aaron Bratcher
Aaron Bratcher

Reputation: 6451

You'll need to add some sort of delay on that initial presentViewController call as illustrated below:

override func viewDidAppear(animated: Bool) {
    presentViewController(UIViewController(), animated: true) { () -> Void in
        self.delay(0.1, closure: { () -> () in
            self.dismissViewControllerAnimated(true, completion: nil)
        })
    }
}


func delay(delay:Double, closure:()->()) {
    dispatch_after(
        dispatch_time(
            DISPATCH_TIME_NOW,
            Int64(delay * Double(NSEC_PER_SEC))
        ),
        dispatch_get_main_queue(), closure)
}

It seems the completion block is called before the animation is truly complete.

Upvotes: 1

Related Questions