在 unwind segue 之后执行 push segue

Posted

技术标签:

【中文标题】在 unwind segue 之后执行 push segue【英文标题】:Perform push segue after an unwind segue 【发布时间】:2014-12-15 12:15:21 【问题描述】:

我正在开发一个相机应用程序,其中相机视图以模态方式显示。在我完成裁剪之后。我对MainPageViewController 进行了放松转场。 (请看截图)

我在MainPageViewController里面的unwind函数如下;

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

其中“categories”是从MainPageViewControllerCategoriesTableViewController 的push segue 标识符。

程序进入unwindToMainMenu 函数但不执行push segue。知道如何解决这个问题吗?

注意:我找到了相同的 question,但答案建议更改情节提要结构。

【问题讨论】:

这是否正确展开到MainPageViewController 我可以正常展开,但是我想在我展开到MainPageViewController后立即执行push segue 你可以赶上segue的结尾。看到那个问题:***.com/questions/18310396/… 【参考方案1】:

聚会有点晚了,但我找到了一种不使用状态标志的方法

注意:这仅适用于 ios 9+,因为只有自定义转场支持 iOS9 之前的类名,并且您不能将退出转场声明为故事板中的自定义转场

1。使用 UIStoryboardSegueWithCompletion 子类化 UIStoryboardSegue

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

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

2。将 UIStoryBoardSegueWithCompletion 设置为退出 segue 的类

注意:此 segue 的操作应为 unwindToMainMenu 以匹配原始问题

3。更新你的 unwind @IBAction 以在完成处理程序中执行代码

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

您的代码现在将在 exit segue 完成其转换后执行

【讨论】:

我只能通过将完成包装在过渡协调器中来使其可靠地工作:destinationViewController.transitionCoordinator()?.animateAlongsideTransition(nil, completion: _ in completion() ) @Bringo 这很有趣...如果您正在设置转换协调器,那么也许您可以直接从展开操作设置转换协调器的完成块,而不必通过自定义继续 好吧,因为在 unwind segue 调用期间没有活动转换,因此转换协调器为零(即转换发生在 unwind segue 调用返回后) 这导致我的应用程序出现内存泄漏! :( 您可能希望将弱 self 放在 segue 完成中。让我知道这是否可以解决您的内存泄漏问题,我可以更新答案@TomCalmon【参考方案2】:

我现在想为这个问题提供我自己的解决方案。欢迎任何进一步的回答。

我将一个布尔变量和 viewDidAppear 函数放入MainPageViewController

var fromCamera = false

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

在从CropViewController 执行展开转场之前,我将fromCamera 设置为true。通过这种方式,我仅在执行从裁剪视图展开的展开转场时才执行转场到类别屏幕。

【讨论】:

更可靠的解决方案。但不幸的是,当从模态呈现的视图中展开时,我不得不求助于骇人听闻的解决方案,因为在这种情况下不会调用 viewDidAppear【参考方案3】:

前进this answer(我只有 Objective-C 代码)

子类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

并在动画完成后调用这个完成块。

@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

【讨论】:

【参考方案4】:

接上前两个答案,这里有关于objective c版本的更多细节(我也只有objective-c代码)

    使用 UIStoryboardSegueWithCompletion 子类化 UIStoryboardSegue

    类 UIStoryboardSegueWithCompletion: UIStoryboardSegue var 完成:(() -> 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
    将 UIStoryBoardSegueWithCompletion 设置为退出 segue 的类

注意:这个 segue 的动作应该是 unwindToMainMenu 以匹配原始问题 [显示 segue ui 的图像][1] [图片显示 segue ui 2][2]

从情节提要中选择退出segue 添加自定义类

-(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];
        ;
    

您的代码现在将在 exit segue 完成其转换后执行

【讨论】:

【参考方案5】:

我猜 performSegue 没有触发,因为 unwind segue 还没有完成。目前我唯一能想到的就是使用dispatch_after 延迟调用performSegue。不过,这对我来说似乎很“hacky”。​​

@IBAction func unwindToMainMenu(segue: UIStoryboardSegue) 
    dispatch_after(1, dispatch_get_main_queue())  () -> Void in
        self.performSegueWithIdentifier("Categories", sender: self)
    

【讨论】:

我还找到了一种可能也是“hacky”的方法;我在 unwind 函数和 viewDidAppear 函数中将一个布尔变量设置为 true,如果该布尔变量为 true,我将调用 performForSegue 函数。您如何看待这个解决方案? 我认为这是一个很好的解决方案。 dispatch_after,由于等待时间可变,可能有问题。使用 boolean 和 viewDidAppear 确保 perfromSegue 将在视图准备就绪时执行。【参考方案6】:

exit segue IBAction 方法发生在实际的 unwind segue 完成之前。我遇到了同样的问题并以这种方式解决了(如果您不介意我对您的代码的解释)。它避免了依赖 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)

希望这对遇到此问题并只想立即过渡的其他人有所帮助!

【讨论】:

【参考方案7】:

更新了@moride 对 Swift 5 的回答。过渡协调器现在是可选的,所以如果是这种情况,我们会立即运行完成。

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

【讨论】:

以上是关于在 unwind segue 之后执行 push segue的主要内容,如果未能解决你的问题,请参考以下文章

从 Unwind segue 触发时,Push segue 不起作用

以编程方式执行 unwind segue

如何以编程方式执行Unwind segue?

如何在没有动画的情况下执行 unwind segue?

无法以编程方式执行 unwind segue

无法在选择搜索结果时执行 unwind segue - 导航堆栈将不会更新