在 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”是从MainPageViewController
到CategoriesTableViewController
的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的主要内容,如果未能解决你的问题,请参考以下文章