Prevent segue in prepareForSegue method?

IosCocoa TouchUiviewcontrollerStoryboardSegue

Ios Problem Overview


Is it possible to cancel a segue in the prepareForSegue: method?

I want to perform some check before the segue, and if the condition is not true (in this case, if some UITextField is empty), display an error message instead of performing the segue.

Ios Solutions


Solution 1 - Ios

It's possible in iOS 6 and later: You have to implement the method

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

In your view controller. You do your validation there, and if it's OK then return YES; if it's not then return NO; and the prepareForSegue is not called.

Note that this method doesn't get called automatically when triggering segues programmatically. If you need to perform the check, then you have to call shouldPerformSegueWithIdentifier to determine whether to perform segue.

Solution 2 - Ios

Note: the accepted answer is the best approach if you can target iOS 6. For targeting iOS 5, this answer will do.

I don't believe it is possible to cancel a segue in prepareForSegue. I would suggest moving your logic to the point that the performSegue message is first sent.

If you are using Interface Builder to wire up a segue directly to a control (e.g. linking a segue directly to a UIButton), then you can accomplish this with a bit of refactoring. Wire the segue to the view controller instead of a specific control (delete the old segue link, and then control-drag from the view controller itself to the destination view controller). Then create an IBAction in your view controller, and wire the control to the IBAction. Then you can do your logic (check for empty TextField) in the IBAction you just created, and decide there whether or not to performSegueWithIdentifier programatically.

Solution 3 - Ios

Swift 3: func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool

Return value true if the segue should be performed or false if it should be ignored.

Example:

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
}

Solution 4 - Ios

Alternatively, it's somewhat bad behavior to offer a button that a user shouldn't press. You can leave the segue wired as stands, but start with the button disabled. Then wire the UITextField's "editingChanged" to an event on the view control ala

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

Solution 5 - Ios

Its easy in the swift .

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

Solution 6 - Ios

As Abraham said, check valid or not in the following function.

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

And, the performSegueWithIdentifier:sender: called by programming can be blocked by overwriting following method. By default, it is not checking valid or not by -shouldPerformSegueWithIdentifier:sender:, we can do it manually.

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

Solution 7 - Ios

Swift 4 Answer:

Following is Swift 4 implementation to cancel 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
}

Solution 8 - Ios

Should Perform Segue for Login Register

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

}

Solution 9 - Ios

Similar to Kaolin's answer is to leave the seque wired to the control but validate the control based on conditions in the view. If you're firing on table cell interaction then you also need to set the userInteractionEnabled property as well as disabling the stuff in the cell.

For instance, I've got a form in a grouped table view. One of the cells leads to another tableView that acts as a picker. Whenever a control is changed in the main view I call this method

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

}

Solution 10 - Ios

The other way is to override method of tableView with willSelectRowAt and return nil if you don't want to show the segue. showDetails() - is some bool. In most cases should be implemented in data model being represented in cell with indexPath.

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionShmidtView Question on Stackoverflow
Solution 1 - IosAbrahamView Answer on Stackoverflow
Solution 2 - IosMike MertsockView Answer on Stackoverflow
Solution 3 - IosOrdoDeiView Answer on Stackoverflow
Solution 4 - IosKaolin FireView Answer on Stackoverflow
Solution 5 - IosZumry MohamedView Answer on Stackoverflow
Solution 6 - IosAechoLiuView Answer on Stackoverflow
Solution 7 - IosPankaj KulkarniView Answer on Stackoverflow
Solution 8 - IosSwappyeeView Answer on Stackoverflow
Solution 9 - IosJames MooreView Answer on Stackoverflow
Solution 10 - IosBogdan UstyakView Answer on Stackoverflow