在prepareForSegue方法中防止segue?


249

是否可以取消该prepareForSegue:方法中的序列?

我想在segue之前执行一些检查,并且如果条件不成立(在这种情况下,如果其中一些UITextField为空),则显示错误消息而不是执行segue。

Answers:


485

在iOS 6和更高版本中可能:您必须实现方法

- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender 

在您的视图控制器中。你做你的验证那里,如果是OK,然后return YES;,如果它不是那么return NO;与prepareForSegue不叫。

请注意,以编程方式触发segues时不会自动调用此方法。如果需要执行检查,则必须调用shouldPerformSegueWithIdentifier来确定是否执行segue。


106
仅供参考,如果通过调用[self performSegueWithIdentifier:@“ segueIdentifier” sender:nil]以编程方式触发了segue;shouldPerformSegueWithIdentifier将永远不会被调用。
花花公子

3
@Thedude感谢您指出这一点。正在跟踪问题,但没有达到我的断点。对于任何好奇的人,您只需要调用包装在if语句中的此方法即可获得相同的结果。
jpittman 2013年

1
@jpittman请您解释一下if语句中的含义是什么?
Boda Taljo 2014年

7
@AubadaTaljo:(道歉格式化) if ([self shouldPerformSegueWithIdentifier:@"segueIdentifier" sender:nil]) { [self performSegueWithIdentifier:@"segueIdentifier" sender:nil]; }
TimMedcalf

在iOS 11.3 SDK中从情节提要segue进行了尝试,并且“ shouldPerformSegueWithIdentifier”确实被自动调用
Menno

52

注意:如果可以将iOS 6作为目标,则可接受的答案是最佳方法。对于iOS 5,可以使用此答案。

我不认为有可能取消的扣押prepareForSegue。我建议将您的逻辑转移到performSegue消息首次发送的地步。

如果您正在使用Interface Builder将连接直接连接到控件(例如,将连接直接链接到UIButton),则可以通过一些重构来实现。将segue连接到视图控制器而不是特定控件(删除旧的segue链接,然后将控件从视图控制器本身拖动到目标视图控制器)。然后IBAction在您的视图控制器中创建一个,并将控件连接到IBAction。然后,您可以在刚刚创建的IBAction中进行逻辑处理(检查是否有空的TextField),并在此确定是否以performSegueWithIdentifier编程方式进行。


如果segue是针对弹出式控制器的,则您希望再次点击该按钮来创建另一个弹出式控制器。在这种情况下,正确的做法是关闭弹出窗口。您的答案允许这种正确的行为。如果直接从情节提要中的按钮进行连接,则无论如何我都看不到正确的行为。
wcochran 2012年

1
经过数小时的令人沮丧的尝试,以使多个基于segue的popover能够很好地配合使用,我放弃了,摆脱了popover的支持,转而使用此解决方案。它实际上使用更少的代码。
mpemburn

这样会不会打败别人的目的?
Cristik '17年

将ViewController链接到ViewController的事实解决了我的问题。谢谢!这是最好的解决方案
TJ博士

19

Swift 3:func shouldPerformSegue(withIdentifier标识符:字符串,发件人:任何?)-> Bool

如果应该执行segue,则返回true;如果应忽略,则返回false

范例

var badParameters:Bool = true

override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
    if badParameters  {
         // your code here, like badParameters  = false, e.t.c
         return false
    }
    return true
}

12

另外,提供用户不应按下的按钮也有些不好的行为。您可以将segue保持原样,但从禁用按钮开始。然后将UITextField的“ editingChanged”连接到视图控件ala上的事件

- (IBAction)nameChanged:(id)sender {
    UITextField *text = (UITextField*)sender;
    [nextButton setEnabled:(text.text.length != 0)];
}

“或者,提供用户不应该按下的按钮是一种不好的行为”。我不同意这一点-这部分是正确的,但实际上取决于上下文。不指导用户也是一种不良行为-例如,他们可以点击按钮,然后系统说明需要首先完成的操作。使用禁用或不可见的按钮,用户将迷路或致电支持...
csmith

11

它容易迅速。

override func shouldPerformSegueWithIdentifier(identifier: String,sender: AnyObject?) -> Bool {

    return true
}

3
??您能否详细说明这个答案?仅代码的答案对于其他读者来说不是很有用……
Cristik

9

正如亚伯拉罕所说,在以下功能中检查是否有效。

- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(nullable id)sender
{
     // Check this identifier is OK or NOT.
}

并且,performSegueWithIdentifier:sender:可以通过覆盖以下方法来阻止编程调用。默认情况下,不是通过来检查是否有效-shouldPerformSegueWithIdentifier:sender:,我们可以手动进行。

- (void)performSegueWithIdentifier:(NSString *)identifier sender:(id)sender
{
    // Check valid by codes
    if ([self shouldPerformSegueWithIdentifier:identifier sender:sender] == NO) {
        return;
    }

    // If this identifier is OK, call `super` method for `-prepareForSegue:sender:` 
    [super performSegueWithIdentifier:identifier sender:sender];
}

这部分[super performSegueWithIdentifier:identifier sender:sender];真的是真的吗?
本·惠勒

@BenWheeler您可以尝试。如果您覆盖performSegueWithIdentifier:sender:方法,而不调用它的super方法。
AechoLiu

5

应该为登录注册执行Segue

-(BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender
{

    [self getDetails];

    if ([identifier isEqualToString:@"loginSegue"])
    {

        if (([_userNameTxtf.text isEqualToString:_uname])&&([_passWordTxtf.text isEqualToString:_upass]))
        {

            _userNameTxtf.text=@"";
            _passWordTxtf.text=@"";

            return YES;
        }
        else
        {
            UIAlertView *loginAlert = [[UIAlertView alloc] initWithTitle:@"Alert" message:@"Invalid Details" delegate:self cancelButtonTitle:@"Try Again" otherButtonTitles:nil];

            [loginAlert show];

            _userNameTxtf.text=@"";
            _passWordTxtf.text=@"";

            return NO;
        }

    }

    return YES;

}

-(void)getDetails
{
    NSArray *dir=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

    NSString *dbpath=[NSString stringWithFormat:@"%@/userDb.sqlite",[dir lastObject]];

    sqlite3 *db;

    if(sqlite3_open([dbpath UTF8String],&db)!=SQLITE_OK)
    {
        NSLog(@"Fail to open datadbase.....");
        return;
    }

    NSString *query=[NSString stringWithFormat:@"select * from user where userName = \"%@\"",_userNameTxtf.text];

    const char *q=[query UTF8String];

    sqlite3_stmt *mystmt;

    sqlite3_prepare(db, q, -1, &mystmt, NULL);

    while (sqlite3_step(mystmt)==SQLITE_ROW)
    {
        _uname=[NSString stringWithFormat:@"%s",sqlite3_column_text(mystmt, 0)];

        _upass=[NSString stringWithFormat:@"%s",sqlite3_column_text(mystmt, 2)];
    }

    sqlite3_finalize(mystmt);
    sqlite3_close(db);

}

4

与高岭土的答案类似,是将序列连接到控件,但根据视图中的条件验证控件。如果要触发表单元格交互,则还需要设置userInteractionEnabled属性以及禁用单元格中的内容。

例如,我在分组表视图中有一个表单。单元格中的一个导致另一个tableView充当选择器。每当在主视图中更改控件时,我都会调用此方法

-(void)validateFilterPicker
{
    if (micSwitch.on)
    {
        filterPickerCell.textLabel.enabled = YES;
        filterPickerCell.detailTextLabel.enabled = YES;
        filterPickerCell.userInteractionEnabled = YES;
        filterPickerCell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    }
    else
    {
        filterPickerCell.textLabel.enabled = NO;
        filterPickerCell.detailTextLabel.enabled = NO;
        filterPickerCell.userInteractionEnabled = NO;
        filterPickerCell.accessoryType = UITableViewCellAccessoryNone;
    }

}

4

Swift 4答案:

以下是Swift 4实施以取消segue:

override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
    if identifier == "EditProfile" {
        if userNotLoggedIn {
            // Return false to cancel segue with identified Edit Profile
            return false
        }
    }
    return true
}

2

另一种方法是使用willSelectRowAt重写tableView的方法,如果不想显示顺序,则返回nil。 showDetails()-是个布尔。在大多数情况下,应在以表示的单元格中的数据模型中实现indexPath

 func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
        if showDetails() {
                return indexPath            
        }
        return nil
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.