2012-03-08 18 views
32

Questa potrebbe essere una domanda molto semplice, ma non ha dato alcun risultato durante la ricerca di esso in modo qui è ...Come verificare se un controller di vista in grado di eseguire un segue

Sto cercando di elaborare un modo per verificare se un determinato controller di visualizzazione può eseguire un seguito con l'identificatore XYZ prima di chiamare il metodo performSegueWithIdentifier:.

Qualcosa sulla falsariga di:

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

possibile?

+0

Esattamente la domanda che sto cercando la risposta in questo momento ... –

+1

Hey Dan I finito per usare '@try @catch @ finally'. Funziona bene. – Rog

+0

L'ho fatto anche io, spero davvero che ci sia davvero un modo per controllarlo. Di regola, cerco di evitare situazioni in cui un'eccezione potrebbe essere generata durante normali situazioni di runtime. –

risposta

7

Come indicato nella documentazione:

applicazioni normalmente non è necessario per attivare direttamente segues. Invece, si configura un oggetto in Interface Builder associato a il controller di visualizzazione, ad esempio un controllo incorporato nella sua gerarchia di viste, per attivare il seguito. Tuttavia, è possibile chiamare questo metodo per attivare a livello di codice uno spostamento , magari in risposta a un'azione che non è possibile specificare nel file di risorse dello storyboard. Ad esempio, è possibile chiamare da un gestore di azioni personalizzato utilizzato per elaborare gli eventi dell'accelerometro o degli accelerometri .

Il controller di visualizzazione che riceve questo messaggio deve essere stato caricato da uno storyboard. Se il controller della vista non ha uno storyboard associato, forse perché lo hai allocato e inizializzato da solo, questo metodo genera un'eccezione.

Detto questo, quando si attiva la segue, normalmente è perché si presume che il UIViewController sarà in grado di rispondere ad essa con una specifica segue's identificatore. Sono d'accordo anche con Dan F, dovresti cercare di evitare situazioni in cui potrebbe essere lanciata un'eccezione. Per quanto il motivo per voi di non essere in grado di fare qualcosa del genere:

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

sto indovinando che:

  1. respondsToSelector: verifica solo se si è in grado di gestire tale messaggio in fase di esecuzione. In questo caso è possibile, perché la classe UIViewController è in grado di rispondere a performSegueWithIdentifier:sender:. Per verificare effettivamente se un metodo è in grado di gestire un messaggio con determinati parametri, suppongo che sarebbe impossibile, perché per determinare se è possibile deve effettivamente farlo funzionare e quando lo fa lo NSInvalidArgumentException aumenterà.
  2. Per creare effettivamente ciò che hai suggerito, sarebbe utile ricevere un elenco di id di seguito a cui è associato lo UIViewController. Dal UIViewControllerdocumentation, non ero in grado di trovare qualcosa che assomiglia a quello

Per il momento, sto indovinando la soluzione migliore è andare avanti con la @try@catch@finally.

-1

Non c'è modo di verificare che utilizzando le funzioni standard, ciò che si può fare è sottoclasse UIStoryboardSegue e memorizzare le informazioni nel controller di visualizzazione source (che viene passato al costruttore).Nel builder dell'interfaccia seleziona "Personalizzato" come tipo di seguito come digita il nome della classe del tuo seguito, quindi il costruttore verrà richiamato per ogni istanza successiva e puoi interrogare i dati memorizzati se esiste.

È inoltre necessario eseguire l'override del metodo perform di chiamare [source presentModalViewController:destination animated:YES] o [source pushViewController:destination animated:YES] a seconda del tipo di transizione che si desidera.

+0

La chiamata al presente, al push e al pop a livello di codice è molto pericolosa perché i passaggi possono essere modificati in qualsiasi momento da un modello a una scena spinta. Quando si apre un modale, si blocca. È meglio essere sicuri che il nome indicato esista o utilizzare try/catch che ritengo sia ancora piuttosto trascurato dal momento che non è veramente eccezionale. Ci dovrebbe essere un metodo per verificare se un identificatore di follow è definito. Questo sembra mancare di proposito. – Brennan

24

Per verificare se il seguito esisteva o meno, ho semplicemente circondato la chiamata con un blocco try-and-catch. Si prega di vedere il codice di esempio di seguito:

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

Spero che questo aiuti.

+1

Questa soluzione funziona alla grande. Si noti che se si dispone di un punto di interruzione di eccezione, si interromperà comunque. Puoi comunque continuare senza schiantarsi. – VaporwareWolf

+1

È possibile che si verifichino perdite di memoria in ARC perché non vengono eliminate dopo l'eccezione. – Andy

+0

Non usare questo. Come ha detto Andy, il controllore della vista invierà il messaggio 'performSegueWithIdentifier: sender:' e tutto il suo controller di visualizzazione figlio (perché Uikit mantiene il controller della vista ma non ha mai la possibilità di rilasciarlo a causa dell'eccezione). –

3

È possibile eseguire l'override di - (BOOL) shouldPerformSegueWithIdentifier: mittente: metodo e fare la logica lì.

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

Spero che questo aiuti.

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

Grazie a questo è utile sapere (anche se è un comportamento non documentato). – Rog

+0

Mi dispiace di avere solo un upvote da dare. Ottimo uso dei predicati, Evgeny. –

+0

NB in ​​base alla risposta all'indirizzo http://stackoverflow.com/a/35060917/305913, l'utilizzo di questo comportamento non documentato potrebbe causare il rifiuto dell'app dall'app store. –

1

versione Swift della risposta di Evgeny Mikhaylov, che ha funzionato per me:

ho riutilizzare un controller per due punti di vista. Questo mi aiuta a riutilizzare il codice.

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) 
} 
+0

Credo che il nome di questo metodo sia riservato in iOS, poiché sto riscontrando un comportamento inaspettato utilizzando questo approccio. È meglio rinominarlo, ad es. a 'canRunSegueWithIdentifier' –

9

Ecco un più corretto modo Swift per verificare se un segue esiste:

extension UIViewController { 
    func canPerformSegue(id: String) -> Bool { 
     let segues = self.valueForKey("storyboardSegueTemplates") as? [NSObject] 
     let filtered = segues?.filter({ $0.valueForKey("identifier") as? String == id }) 
     return (filtered?.count > 0) ?? false 
    } 

    // Just so you dont have to check all the time 
    func performSegue(id: String, sender: AnyObject?) -> Bool { 
     if canPerformSegue(id) { 
      self.performSegueWithIdentifier(id, sender: sender) 
      return true 
     } 
     return false 
    } 
} 

// 1 
if canPerformSegue("test") { 
    self.performSegueWithIdentifier("test", sender: nil) 
} 

// 2 
performSegue("test", sender: nil) 
Problemi correlati