问题
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