Attempt to present UIViewController while a presen

2019-05-23 16:27发布

问题:

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?

回答1:

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.



回答2:

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
            }
        }
    }
}