Perform push segue after an unwind segue

前端 未结 7 2354
失恋的感觉
失恋的感觉 2020-12-05 02:24

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. (

相关标签:
7条回答
  • 2020-12-05 02:50

    I'm guessing the performSegue is not firing because the unwind segue has not yet finished. The only thing I can think of at the moment, is to delay calling the performSegue using dispatch_after. This seems very "hacky" to me though.

    @IBAction func unwindToMainMenu(segue: UIStoryboardSegue) {
        dispatch_after(1, dispatch_get_main_queue()) { () -> Void in
            self.performSegueWithIdentifier("Categories", sender: self)
        }
    }
    
    0 讨论(0)
  • 2020-12-05 02:53

    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

    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

    0 讨论(0)
  • 2020-12-05 02:56

    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
    
    0 讨论(0)
  • 2020-12-05 02:57

    Taking forward the previous two answers, there is a bit more detail about the objective c version here (I too only had Objective-C code)

    1. Subclass UIStoryboardSegue with UIStoryboardSegueWithCompletion

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

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

      }

    UIStoryboardSegueWithCompletion.h

    #import <UIKit/UIKit.h>
    
    @interface MyStoryboardSegue : UIStoryboardSegueWithCompletion
    
    @property (nonatomic, copy) void(^completion)();
    
    @end
    

    UIStoryboardSegueWithCompletion.m

    #import "UIStoryboardSegueWithCompletion.h"
    
    @implementation UIStoryboardSegueWithCompletion
    
    - (void)perform {
      [super perform];
      if (self.completion != nil) {
        [self.destinationViewController.transitionCoordinator
         animateAlongsideTransition:nil
         completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
           if (![context isCancelled]) {
             self.completion();
           }
         }];
      }
    }
    @end
    
    1. Set UIStoryBoardSegueWithCompletion as the class for your exit segue

    note: the action for this segue should be unwindToMainMenu to match the original question [image showing segue ui][1] [image showing segue ui 2][2]

    Select exit segue from storyboard Add custom class

    -(IBAction)unwindToMainMenu(UIStoryboardSegue *)segue {
        if([segue isKindOfClass:[UIStoryboardSegueWithCompletion class]]){
            UIStoryboardSegueWithCompletion *segtemp = segue;// local prevents warning
            segtemp.completion = ^{
                NSLog(@"segue completion");
                [self performSegueWithIdentifier:@"Categories" sender:self];
            };
        }
    }
    

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

    0 讨论(0)
  • 2020-12-05 02:57

    The exit segue IBAction method happens before the actual unwind segue is finished. I had the same issue and resolved it this way (if you don't mind my paraphrasing of your code). It avoids the extra time and animations from relying on ViewDidAppear.

    @IBAction func unwindToMainMenu(segue: UIStoryboardSegue) {
       let categoriesTable = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("CategoryTableViewController")
       self.navigationController?.viewControllers.append(categoriesTable)
       self.navigationController?.showViewController(categoriesTable, sender: self)
    }
    

    Hope this is helpful for anyone else who runs into this and just wants an instantaneous transition!

    0 讨论(0)
  • 2020-12-05 02:59

    Updated @moride's answer for Swift 5. The transition coordinator is now optional, so we run completion immediately if this is the case.

    class UIStoryboardSegueWithCompletion: UIStoryboardSegue {
        var completion: (() -> Void)?
    
        override func perform() {
            super.perform()
    
            guard let completion = completion else { return }
            guard let coordinator = destination.transitionCoordinator else {
                completion()
                return
            }
    
            coordinator.animate(alongsideTransition: nil) { context in
                guard !context.isCancelled else { return }
                completion()
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题