调用performSegueWithIdentifier不会调用shouldPerformSegueWithIdentifier函数

47

我有两个视图控制器。在视图控制器1上,我拥有以下内容:

  • 一个将我带到视图控制器2的segue - 这个segue的名称为“showme”,并且附加在视图控制器上
  • 一个用于UIButton的IBAction

在我的代码中,我有以下处理按钮按下操作的代码:

@IBAction func buttonPress(sender: AnyObject) {
    println("button pressed")
        performSegueWithIdentifier("showme", sender: self)
}

我还有以下方法:

override func shouldPerformSegueWithIdentifier(identifier: String?, sender: AnyObject?) -> Bool {
    println("Should performing....")
    return true
}   

由于某些原因,shouldPerformSegueWithIdentifier函数从未被调用。但是,如果我直接在UIButton上添加到ViewController2的segue,则会被调用。

我已确认在按钮操作中调用它的方向是有效的(请参见下面的代码),但我不认为这是它的工作方式。prepareforSegue同样如此。

@IBAction func buttonPress(sender: AnyObject) {
    println("button pressed")
    if (shouldPerformSegueWithIdentifier("showme", sender: self)){
        performSegueWithIdentifier("showme", sender: self)}
} 

3
嘿@es3dev,你能在我的答案中勾选绿色复选框吗? :) - nburk
5个回答

84

下面是这种行为完全自然的原因:

1)shouldPerformSegueWithIdentifier用于确保在Storyboards中设置的segue应该被触发,因此shouldPerformSegueWithIdentifier仅在Storyboard Segues情况下才会被调用,并给您提供了实际执行segue的机会。

2)当您自己调用performSegueWithIdentifier时,shouldPerformSegueWithIdentifier 不会被调用,因为可以假设您知道自己在做什么。如果从shouldPerformSegueWithIdentifier返回NO,那么调用performSegueWithIdentifier将毫无意义。


如果是这种情况,那么我的segue就无法从UIButton设置,因为即使我在那个IBAction中什么都不做,segue也会被执行。相反,segue应该从视图控制器设置... 对吗? - es3dev
2
一旦你知道答案,这就显而易见了...现在,由于你,我知道了答案!谢谢! - Scooter

34

@nburk的答案是完全正确的。

然而,我理解在某些情况下,即使代码中调用了performSegueWithIdentifier:sender:方法,调用shouldPerformSegueWithIdentifier:sender:方法也会非常有用。

例如,我们想要对是否执行segue进行一些验证,我们希望将这个逻辑放在一个地方,并避免在各处重复编写以下条件:

if (self.shouldPerformSegue) {
     [self performSegueWithIdentifier:identifier sender:sender];
}

可以通过以下方式轻松地覆盖 performSegueWithIdentifier:sender: 来实现:

- (void)performSegueWithIdentifier:(NSString *)identifier sender:(id)sender
{
    if ([self shouldPerformSegueWithIdentifier:identifier sender:sender]) {
        [super performSegueWithIdentifier:identifier sender:sender];
    }
    // otherwise do nothing
}

- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender
{
    return self.shouldPerformSegue;
}

通过使用shouldPerformSegueWithIdentifier:sender:,您可以定义逻辑以允许/拒绝IB和代码触发的segue。


这是一个实用的解决方案。 - josefdlange
完美的答案。对于所有VC来说都是必备的修复程序。我将把它放入我的BaseVC中,以便所有VC都能受益。实际上,使用“shouldPerformSegueWithIdentifier”,代码行数更少,segue可以在同一个VC中通过编程和storyboard两种方式实现。 - John Pang

3

感谢 @tanzolone 提供的完美解决方案。我已经将代码重写为 Swift 5

如果想要在执行 performingSegue 前强制调用 shouldPerformSegue,可以在你的类中覆盖 performingSegue

override func performSegue(withIdentifier identifier: String, sender: Any?) {
    if shouldPerformSegue(withIdentifier: identifier, sender: sender) {
        super.performSegue(withIdentifier: identifier, sender: sender)
    }
}

override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
    // Your code (return true if you want to perform the segue)
}

3
与上面的答案一样。如果您调用performSegueWithIdentifier,则不会调用shouldPerformSegueWithIdentifier
例如:
假设您在容器视图中嵌入了一个segue以显示您可以通过其滑动的某些图像。并且嵌入的segue在加载VC时立即触发。但是,如果您必须从远程API下载图像,则您的应用程序将崩溃,因为没有任何图像可以显示在嵌入的segue /容器视图中。
在这种情况下,将需要shouldPerformSegueWithIdentifier
您可以设置一个布尔值,在其中检查shouldPerformSegueWithIdentifier,如果为false,则返回false,您的segue将不会被触发。一旦您的应用程序已下载图像,您就可以调用performSegueWithIdentifier

0
如果您正在使用此代码,则需要删除以下内容:
[self performSegueWithIdentifier:name sender:sender];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接