web-dev-qa-db-fra.com

Empêcher le segue dans la méthode prepareForSegue?

Est-il possible d'annuler une séquence dans la méthode prepareForSegue:?

Je souhaite effectuer certaines vérifications avant la transition et si la condition n'est pas vraie (dans ce cas, si des valeurs UITextField sont vides), affichez un message d'erreur au lieu d'effectuer la conversion.

247
Shmidt

C'est possible dans iOS 6 et versions ultérieures: vous devez implémenter la méthode

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

Dans votre contrôleur de vue. Vous faites votre validation ici, et si tout va bien, alors return YES; si ce n'est pas le cas return NO; et le prepareForSegue n'est pas appelé.

Notez que cette méthode n'est pas appelée automatiquement lors du déclenchement de segments par programmation. Si vous devez effectuer cette vérification, vous devez appeler le paramètre shouldPerformSegueWithIdentifier pour déterminer si vous souhaitez effectuer la transition.

477
Abraham

Remarque: la réponse acceptée est la meilleure approche si vous pouvez cibler iOS 6. Cette réponse convient pour cibler iOS 5.

Je ne crois pas qu'il soit possible d'annuler une transition dans prepareForSegue. Je suggérerais de déplacer votre logique au point que le message performSegue soit d'abord envoyé.

Si vous utilisez Interface Builder pour connecter directement une séquence à un contrôle (par exemple, en reliant une séquence directement à un UIButton), vous pouvez le faire en procédant à une refactorisation. Câblez la séquence au contrôleur de vue au lieu d'un contrôle spécifique (supprimez l'ancien lien de séquence, puis faites glisser la souris du contrôleur de vue au contrôleur de vue de destination). Créez ensuite un IBAction dans votre contrôleur de vue, puis connectez le contrôle à IBAction. Ensuite, vous pouvez faire votre logique (rechercher un TextField vide) dans l’IBAction que vous venez de créer et décider de lui attribuer ou non performSegueWithIdentifier par programme.

51
Mike Mertsock

Swift: func shouldPerformSegue (withIdentifier identifier: String, expéditeur: Any?) -> Bool

Valeur de retour true si la séquence doit être effectuée ou false si elle doit être ignorée.

Exemple:

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
}
15
OrdoDei

Alternativement, c’est un peu mauvais comportement de proposer un bouton sur lequel un utilisateur ne devrait pas appuyer. Vous pouvez laisser la séquence câblée en tant que pied, mais commencez avec le bouton désactivé. Ensuite, connectez le "montageChangé" de UITextField à un événement sur le contrôle de vue

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

C'est facile dans le Swift.

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

    return true
}
11
Zumry Mohamed

Comme Abraham a dit, vérifier valide ou non dans la fonction suivante.

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

Et, le performSegueWithIdentifier:sender: appelé par programmation peut être bloqué en écrasant la méthode suivante. Par défaut, il ne vérifie pas valide ou pas par -shouldPerformSegueWithIdentifier:sender:, nous pouvons le faire manuellement.

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

Devrait effectuer Segue pour la connexion

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

}
5
Swappyee

Réponse rapide 4:

Voici la mise en œuvre de Swift 4 pour annuler la transition:

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
}
4
Pankaj Kulkarni

La réponse de Kaolin est similaire à celle de laisser le seque connecté au contrôle, mais de valider le contrôle en fonction des conditions de la vue. Si vous utilisez l'interaction de cellule de tableau, vous devez également définir la propriété userInteractionEnabled et désactiver les éléments de la cellule.

Par exemple, j'ai un formulaire dans une vue de table groupée. Une des cellules mène à une autre tableView qui agit en tant que sélecteur. Chaque fois qu'un contrôle est modifié dans la vue principale, j'appelle cette méthode

-(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
James Moore

L'autre méthode consiste à remplacer la méthode tableView par willSelectRowAt et à renvoyer nil si vous ne souhaitez pas afficher la séquence. showDetails() - est un peu bool. Dans la plupart des cas, il convient de mettre en œuvre le modèle de données représenté dans la cellule avec indexPath.

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