【问题标题】:Prevent segue in prepareForSegue method?在prepareForSegue方法中防止segue?
【发布时间】:2011-12-25 09:01:25
【问题描述】:

是否可以取消prepareForSegue: 方法中的转场?

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

【问题讨论】:

    标签: ios cocoa-touch uiviewcontroller storyboard segue


    【解决方案1】:

    在 iOS 6 及更高版本中是可能的: 你必须实现方法

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

    在您的视图控制器中。您在那里进行验证,如果可以,则 return YES;,如果不是,则 return NO; 并且不会调用 prepareForSegue。

    请注意,当以编程方式触发 segue 时,不会自动调用此方法。如果需要进行检查,则需要调用 shouldPerformSegueWithIdentifier 来判断是否进行segue。

    【讨论】:

    • 仅供参考,如果通过调用 [self performSegueWithIdentifier:@"segueIdentifier" sender:nil] 以编程方式触发 segue; shouldPerformSegueWithIdentifier 永远不会被调用。
    • @Thedude 感谢您指出这一点。正在追踪一个问题,但它没有达到我的断点。对于任何好奇的人,您只需要在 if 语句中调用此方法即可获得相同的结果。
    • @jpittman 你能解释一下你在 if 语句中包裹的意思吗?
    • @AubadaTaljo:(为格式化道歉)if ([self shouldPerformSegueWithIdentifier:@"segueIdentifier" sender:nil]) { [self performSegueWithIdentifier:@"segueIdentifier" sender:nil]; }
    • 在 iOS 11.3 SDK 中从故事板 segue 中尝试过这个,“shouldPerformSegueWithIdentifier”确实被自动调用了
    【解决方案2】:

    注意:如果您可以定位 iOS 6,则接受的答案是最好的方法。对于定位 iOS 5,这个答案就可以了。

    我认为取消prepareForSegue 中的转场是不可能的。我建议将您的逻辑转移到首先发送 performSegue 消息的程度。

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

    【讨论】:

    • 如果segue 是一个popover 控制器,你确实想要第二次点击按钮来创建另一个popover 控制器;在这种情况下,正确的做法是关闭弹出框。您的回答允许这种正确的行为。如果您直接从情节提要中的按钮连接它,我无论如何都看不到获得正确的行为。
    • 经过几个令人沮丧的小时试图让多个基于 segue 的弹出框很好地一起播放后,我放弃并摆脱了弹出框序列,转而支持这个解决方案。它实际上使用了更少的代码。
    • 这不会破坏使用 segues 的目的吗?
    • 将 ViewController 链接到 ViewController 的事实解决了我的问题。谢谢!这是最好的解决方案
    【解决方案3】:

    斯威夫特 3: func shouldPerformSegue(withIdentifier identifier: String, 发件人:有吗?) -> 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
    }
    

    【讨论】:

      【解决方案4】:

      另外,提供一个用户不应该按下的按钮有点不好。您可以将 segue 保留为支架,但从禁用按钮开始。然后将 UITextField 的“editingChanged”连接到视图控件 ala 上的事件

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

      【讨论】:

      • “另外,提供一个用户不应该按下的按钮是一种不好的行为”。我不同意这一点 - 这部分是正确的,但实际上取决于上下文。不引导用户也是不好的行为——例如,他们可以点击一个按钮,系统会解释首先需要做什么。使用禁用或不可见的按钮,用户要么会迷路,要么会致电支持...
      【解决方案5】:

      它在 swift 中很容易。

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

      【讨论】:

      • 嗯?你能详细说明这个答案吗?纯代码答案对更多读者来说不是很有用...
      【解决方案6】:

      As Abraham said,在下面的函数中检查是否有效。

      - (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 方法。
      【解决方案7】:

      斯威夫特 4 答案:

      以下是取消 segue 的 Swift 4 实现:

      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
      }
      

      【讨论】:

        【解决方案8】:

        应该为登录注册执行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);
        
        }
        

        【讨论】:

          【解决方案9】:

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

          例如,我在分组表视图中有一个表单。其中一个细胞导致另一个符合作为选择器的表观。每当在主视图中更改控件时,我都会调用此方法

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

          【讨论】:

            【解决方案10】:

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

             func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
                    if showDetails() {
                            return indexPath            
                    }
                    return nil
                }
            

            【讨论】:

              猜你喜欢
              • 2017-04-16
              • 2013-12-31
              • 2012-02-16
              • 1970-01-01
              • 1970-01-01
              • 2023-04-04
              • 2012-05-14
              • 2012-01-11
              • 1970-01-01
              相关资源
              最近更新 更多