问题
Within my app I'm having an issue with the following error:
Pushing the same view controller instance more than once is not supported
It's a bug report that's comeback from a few users. We've tried to replicate it but can't (double tapping buttons etc). This is the line we use to open the view controller:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let editView = storyboard.instantiateViewControllerWithIdentifier("EditViewController") as! EditViewController
editView.passedImage = image
editView.navigationController?.setNavigationBarHidden(false, animated: false)
if !(self.navigationController!.topViewController! is EditViewController) {
self.navigationController?.pushViewController(editView, animated: true)
}
Anybody have any ideas? I've done a bit of research and most answers on Stack we've covered so are at a bit of a loss for how to investigate.
回答1:
Try this to avoid pushing the same VC twice:
if !(self.navigationController!.viewControllers.contains(editView)){
self.navigationController?.pushViewController(editView, animated:true)
}
回答2:
As the pushViewController is asynchronous since iOS7, if you tap the button that push view controller too fast, it will be pushed twice.
I have met such issue, the only way I tried is to set a flag when push is invoked (i.e - navigationController:willShowViewController:animated:
) and unset the flag when the delegate of UINavigationController is called - navigationController:didShowViewController:animated:
It's ugly, but it can avoid the twice-push issue.
回答3:
In the function that does the push:
guard navigationController?.topViewController == self else { return }
回答4:
The completion block of CATransaction
to the rescue :)
The animation of pushViewController(:animated:)
is actually pushed onto the CATransaction
stack, which is created by each iteration of the run loop
. So the completion block of the CATransaction
will be called once the push
animation is finished.
We use a boolean variable isPushing
to make sure new view controller can't be pushed while already pushing one.
class MyNavigationController: UINavigationController {
var isPushing = false
override func pushViewController(_ viewController: UIViewController, animated: Bool) {
if !isPushing {
isPushing = true
CATransaction.begin()
CATransaction.setCompletionBlock {
self.isPushing = false
}
super.pushViewController(viewController, animated: animated)
CATransaction.commit()
}
}
}
来源:https://stackoverflow.com/questions/37829721/pushing-view-controller-twice