webentwicklung-frage-antwort-db.com.de

So prüfen Sie, ob ein View-Controller ein Segment ausführen kann

Dies ist möglicherweise eine sehr einfache Frage, die jedoch bei der Suche zu keinem Ergebnis geführt hat.

Ich versuche, einen Weg zu finden, um zu überprüfen, ob ein bestimmter View-Controller vor dem Aufruf der performSegueWithIdentifier:-Methode ein Segment mit dem Bezeichner XYZ ausführen kann.

Etwas in der Art von:

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

Möglich?

33
Rog

Wie in der Dokumentation angegeben:

Apps müssen normalerweise keine Segmente direkt auslösen. Stattdessen konfigurieren Sie ein Objekt in Interface Builder, das dem Sicht-Controller Zugeordnet ist, beispielsweise ein in seine Ansichtshierarchie eingebettetes Steuerelement, . das Segue auslösen. Sie können diese Methode jedoch aufrufen, um eine - Segmentierung programmatisch auszulösen, möglicherweise als Reaktion auf eine Aktion, die Nicht in der Storyboard-Ressourcendatei angegeben werden kann. Zum Beispiel könnten Sie Von einem benutzerdefinierten Aktionshandler aufrufen, der zum Verarbeiten von Shake- oder Beschleunigungsmessereignissen verwendet wird.

Der View Controller, der diese Nachricht empfängt, muss Von einem Storyboard geladen worden sein. Wenn dem View-Controller kein Storyboard zugeordnet ist, möglicherweise weil Sie es selbst zugewiesen und initialisiert haben, , Gibt diese Methode eine Ausnahme aus.

Das heißt, wenn Sie segueauslösen, liegt dies normalerweise daran, dass UIViewControllerin der Lage ist, mit einem bestimmten segue's-Bezeichner darauf zu reagieren. Ich stimme auch mit Dan F überein. Sie sollten versuchen, Situationen zu vermeiden, in denen eine Ausnahme ausgelöst werden könnte. Als Grund für Sie, so etwas nicht tun zu können:

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

Ich vermute, dass:

  1. respondsToSelector: prüft nur, ob Sie diese Nachricht in Runtime verarbeiten können. In diesem Fall ist dies möglich, da die Klasse UIViewControllerauf performSegueWithIdentifier:sender: antworten kann. Um wirklich zu überprüfen, ob eine Methode eine Nachricht mit bestimmten Parametern verarbeiten kann, ist dies vermutlich nicht möglich. Um festzustellen, ob dies möglich ist, muss sie tatsächlich ausgeführt werden. Wenn dies geschieht, steigt der NSInvalidArgumentExceptionan.
  2. Um tatsächlich das zu erstellen, was Sie vorgeschlagen haben, ist es hilfreich, eine Liste mit der ID des Segue-Objekts zu erhalten, mit der UIViewControllerverknüpft ist. Aus der UIViewControllerDokumentation konnte ich nichts finden, was so aussieht

Im Moment denke ich, dass Sie am besten mit dem @try@catch@finally weitermachen.

6
Rui Peres

Um zu prüfen, ob das Segment existiert oder nicht, habe ich den Anruf einfach mit einem Try-and-Catch-Block umgeben. Bitte sehen Sie das Codebeispiel unten:

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

Hoffe das hilft.

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

Dieser Beitrag wurde für Swift 4 aktualisiert.


Hier ist ein genauerer schneller Weg, um zu überprüfen, ob ein Segment existiert:

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

Sie können die - (BOOL) shouldPerformSegueWithIdentifier: sender: -Methode überschreiben und Ihre Logik dort ausführen. 

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

Hoffe das hilft.

3
ffxfiend

Schnelle Version von Evgeny Mikhaylovs Antwort, die für mich funktionierte:

Ich verwende einen Controller für zwei Ansichten. Dies hilft mir, Code wiederzuverwenden.

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

Referenz 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