Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perform push segue after an unwind segue

I am working on a camera app where the camera views are shown modally. After I am done with cropping. I perform an unwind segue to the MainPageViewController. (Please see the screenshot)

storyboard

My unwind function inside MainPageViewController is as follows;

@IBAction func unwindToMainMenu(segue: UIStoryboardSegue) {
    self.performSegueWithIdentifier("Categories", sender: self)
}

where "categories" is the push segue identifier from MainPageViewController to CategoriesTableViewController.

The program enters the unwindToMainMenu function but it does not perform the push segue. Any idea how to fix this?

Note: I found the same question but the answer suggests to change the storyboard structure.

like image 829
Berkan Ercan Avatar asked Dec 15 '14 12:12

Berkan Ercan


3 Answers

A bit late to the party but I found a way to do this without using state flags

Note: this only works with iOS 9+, as only custom segues support class names prior to iOS9 and you cannot declare an exit segue as a custom segue in storyboards

1. Subclass UIStoryboardSegue with UIStoryboardSegueWithCompletion

class UIStoryboardSegueWithCompletion: UIStoryboardSegue {
    var completion: (() -> Void)?

    override func perform() {
        super.perform()
        if let completion = completion {
            completion()
        }
    }
}

2. Set UIStoryBoardSegueWithCompletion as the class for your exit segue

note: the action for this segue should be unwindToMainMenu to match the original question

Select exit segue from storyboard Add custom class

3. Update your unwind @IBAction to execute the code in the completion handler

@IBAction func unwindToMainMenu(segue: UIStoryboardSegue) {
    if let segue = segue as? UIStoryboardSegueWithCompletion {
        segue.completion = { 
            self.performSegueWithIdentifier("Categories", sender: self) 
        }
    }
}

Your code will now execute after the exit segue completes its transition

like image 128
wyu Avatar answered Nov 19 '22 06:11

wyu


I want to provide my own solution to this problem for now. Any further answers are always welcome.

I put a boolean variable and viewDidAppear function to MainPageViewController.

var fromCamera = false

override func viewDidAppear(animated: Bool) {
    if fromCamera {
        self.performSegueWithIdentifier("categorySelection", sender: self)
        self.fromCamera = false
    }
}

I set fromCamera to true before I perform unwind segue from CropViewController. By that way, I perform segue to category screen only if an unwind segue from crop view is performed.

like image 12
Berkan Ercan Avatar answered Nov 19 '22 06:11

Berkan Ercan


Taking forward this answer (I only had Objective-C code)

Subclass UIStoryBoardSegue

#import <UIKit/UIKit.h>

@interface MyStoryboardSegue : UIStoryboardSegue

/**
 This block is called after completion of animations scheduled by @p self.
 */
@property (nonatomic, copy) void(^completion)();

@end

And call this completion block after completion of animations.

@implementation MyStoryboardSegue

- (void)perform {
  [super perform];
  if (self.completion != nil) {
    [self.destinationViewController.transitionCoordinator
     animateAlongsideTransition:nil
     completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
       if (![context isCancelled]) {
         self.completion();
       }
     }];
  }
}

@end
like image 6
Ayush Goel Avatar answered Nov 19 '22 06:11

Ayush Goel