web-dev-qa-db-fra.com

Comment vérifier si un contrôleur de vue peut effectuer une transition

C’est peut-être une question très simple mais qui n’a donné aucun résultat lors de la recherche, alors la voici ...

J'essaie de trouver un moyen de vérifier si un certain contrôleur de vue peut effectuer une transition avec l'identificateur XYZ avant d'appeler la méthode performSegueWithIdentifier:.

Quelque chose dans le genre de:

if ([self canPerformSegueWithIdentifier:@"SegueID"])
    [self performSegueWithIdentifier:@"SegueID"];

Possible?

33
Rog

Comme indiqué dans la documentation:

Normalement, les applications n'ont pas besoin de déclencher directement des étapes. Vous configurez plutôt un objet dans Interface Builder associé à Le contrôleur de vue, tel qu'un contrôle intégré à sa hiérarchie de vues, . pour déclencher la transition. Cependant, vous pouvez appeler cette méthode pour déclencher une séquence Par programmation, peut-être en réponse à une action qui ne peut pas spécifier Dans le fichier de ressources du storyboard. Par exemple, vous pouvez L'appeler à partir d'un gestionnaire d'actions personnalisé utilisé pour traiter les événements tremblement ou D'accéléromètre.

Le contrôleur de vue qui reçoit ce message doit avoir été chargé À partir d'un storyboard. Si le contrôleur de vue n'a pas de storyboard Associé, peut-être parce que vous l'avez alloué et initialisé vous-même, Cette méthode lève une exception.

Cela dit, lorsque vous déclenchez la segue, c'est normalement parce qu'il est supposé que la UIViewController pourra y répondre avec un identifiant segue's spécifique. Je suis également d’accord avec Dan F, vous devriez essayer d’éviter les situations où une exception pourrait être levée. La raison pour laquelle vous ne pouvez pas faire quelque chose comme ceci:

if ([self canPerformSegueWithIdentifier:@"SegueID"])
    [self performSegueWithIdentifier:@"SegueID"];

Je devine que:

  1. respondsToSelector: vérifie uniquement si vous êtes capable de gérer ce message au moment de l'exécution. Dans ce cas, vous le pouvez, car la classe UIViewController est capable de répondre à performSegueWithIdentifier:sender:. Pour vérifier si une méthode est capable de gérer un message avec certains paramètres, j'imagine que ce serait impossible, car pour déterminer s'il est possible de le faire, il est nécessaire de l'exécuter et la variable NSInvalidArgumentException augmentera.
  2. Pour créer réellement ce que vous avez suggéré, il serait utile de recevoir une liste des identifiants de segue auxquels la variable UIViewController est associée. De la UIViewControllerdocumentation , je n’ai pas trouvé quoi que ce soit qui ressemble à ça

Pour le moment, votre meilleur pari est de continuer avec le @try@catch@finally.

6
Rui Peres

Pour vérifier si la séquence existait ou non, j'ai simplement entouré l'appel avec un bloc try-and-catch. Veuillez voir l'exemple de code ci-dessous:

@try {
    [self performSegueWithIdentifier:[dictionary valueForKey:@"segue"] sender:self];
}
@catch (NSException *exception) {
    NSLog(@"Segue not found: %@", exception);
}

J'espère que cela t'aides.

25
Michael Miscampbell
- (BOOL)canPerformSegueWithIdentifier:(NSString *)identifier
{
    NSArray *segueTemplates = [self valueForKey:@"storyboardSegueTemplates"];
    NSArray *filteredArray = [segueTemplates filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"identifier = %@", identifier]];
    return filteredArray.count>0;
}
14
Evgeny Mikhaylov

Cet article a été mis à jour pour Swift 4.


Voici un moyen plus correct rapide pour vérifier si une transition existe:

extension UIViewController {
func canPerformSegue(withIdentifier id: String) -> Bool {
        guard let segues = self.value(forKey: "storyboardSegueTemplates") as? [NSObject] else { return false }
        return segues.first { $0.value(forKey: "identifier") as? String == id } != nil
    }

    /// Performs segue with passed identifier, if self can perform it.
    func performSegueIfPossible(id: String?, sender: AnyObject? = nil) {
        guard let id = id, canPerformSegue(withIdentifier: id) else { return }
        self.performSegue(withIdentifier: id, sender: sender)
    }
}

// 1
if canPerformSegue("test") {
    performSegueIfPossible(id: "test") // or with sender: , sender: ...)
}

// 2
performSegueIfPossible(id: "test") // or with sender: , sender: ...)
11
Arbitur

Vous pouvez remplacer la méthode - (BOOL) shouldPerformSegueWithIdentifier: sender: et y faire votre logique. 

- (BOOL) shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender {
    if ([identifier isEqualToString:@"someSegue"]) {
        if (!canIPerformSegue) {
            return NO;
        }
    }
    return YES;    
}

J'espère que cela t'aides.

3
ffxfiend

Version rapide de la réponse d'Evgeny Mikhaylov, qui a fonctionné pour moi:

Je réutilise un contrôleur pour deux vues. Cela m'aide à réutiliser du code.

if(canPerformSegueWithIdentifier("segueFoo")) {
  self.performSegueWithIdentifier("segueFoo", sender: nil)
}
else {
  self.performSegueWithIdentifier("segueBar", sender: nil)
}


func canPerformSegueWithIdentifier(identifier: NSString) -> Bool {
    let templates:NSArray = self.valueForKey("storyboardSegueTemplates") as! NSArray
    let predicate:NSPredicate = NSPredicate(format: "identifier=%@", identifier)

    let filteredtemplates = templates.filteredArrayUsingPredicate(predicate)
    return (filteredtemplates.count>0)
}
1
JoeGalind

Référence CanPerformSegue.Swift

import UIKit

extension UIViewController{
    func canPerformSegue(identifier: String) -> Bool {
        guard let identifiers = value(forKey: "storyboardSegueTemplates") as? [NSObject] else {
            return false
        }
        let canPerform = identifiers.contains { (object) -> Bool in
            if let id = object.value(forKey: "_identifier") as? String {
                return id == identifier
            }else{
                return false
            }
        }
        return canPerform
    }
}
0
yuelong qin