Reputation: 63
I have a complex app when I sometimes need to use performSegueWithIdentifier. I can't replace this with IB triggers, must be done programatically! Sometimes I call them in UIButton's actions or even in delegate methods as collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath)
The problem is that if I trigger the events twice and fast, for example by double tapping an UIButton, I get the destinationViewController pushed twice into the navigationController's stack, which is not what I want. I only want it to be pushed once. prepareforSegue gets call twice as well.
Example:
func addDeal(sender: UIBarButtonItem) {
self.performSegueWithIdentifier("segueDeal", sender: sender)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "segueDeal") {
(segue.destinationViewController as! DealVC).deal = self.deal
}
}
Upvotes: 2
Views: 1317
Reputation: 3251
For me this method was helpful:
override func shouldPerformSegueWithIdentifier(identifier: String?, sender: AnyObject?) -> Bool {
for window in UIApplication.sharedApplication().windows {
if let window = window as? UIWindow {
if let sub = window.subviews.first as? UIAlertView {
return false
}
}
}
return navigationController?.topViewController == self
}
I just move this method to RootViewController, from which every controller in my main hierarchy was inherit. Notice that in method I'm also check if there is UIAlertView
presenting.
Upvotes: 0
Reputation: 9012
Disable the button when this method is called, this will prevent it from being tapped multiple times.
func addDeal(sender: UIBarButtonItem) {
sender.enabled = false
self.performSegueWithIdentifier("segueAddDeal", sender: sender)
}
You will also have to re-enable it when your view re-appears for example:
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
someReferenceToTheButton.enabled = true
}
Hair-Brained Alternative
I've just knocked this together in a sample project as a "more generic way" as requested in the comments. It "works" in the basic use case as shown but I honestly have no idea if it will work in more complex situations. I'm also not particularly happy with it, feels hacky and fragile.
class ViewController: UIViewController {
private var preparingForSegue = false
override func viewWillAppear(animated: Bool) {
preparingForSegue = false
super.viewWillAppear(animated)
}
@IBAction func pushOn(sender: AnyObject) {
// Provided as an example of an attempt to perform 2 segues in quick succession
self.performSegueWithIdentifier("DoPush", sender: self)
self.performSegueWithIdentifier("DoPush", sender: self)
}
override func performSegueWithIdentifier(identifier: String, sender: AnyObject?) {
if !preparingForSegue {
super.performSegueWithIdentifier(identifier, sender: sender)
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
super.prepareForSegue(segue, sender: sender)
preparingForSegue = true
}
}
Upvotes: 3