2013-05-19 6 views
6

in Obj-C uno switch può solo valutare i numeri. Mi piacerebbe essere in grado di usarlo per confrontare classi di oggetti, qualcosa di simile, per esempio:in Obj-C, come potrei fare un'istruzione switch che valuterà le classi, anziché solo i numeri?

switch (currentSubViewController.class) 
{ 
    case UITableViewController.class : 
      <do stuff> 
      break; 
    case UICollectionViewController.class : 
      <do stuff> 
      break; 
} 

Esiste un modo per raggiungere questo obiettivo? Mi piacerebbe davvero essere in grado di utilizzare uno switch perché lo rende così facile da leggere per casi diversi e posso aggiungere più casi in qualsiasi momento. Qualche idea?

+0

Supponendo che tu sia su iPhone, stai avendo un viewController separato per ciascuna delle sottoview? –

+0

sì, un controller di visualizzazione per ciascuno. Davvero, voglio vedere quale controller di visualizzazione è attualmente presentato. Potrei facilmente tenerne traccia usando semplicemente un valore numerico (come globale, o qualsiasi altra cosa), come int currentPresentedController = qualunque cosa, e quindi basta impostare il valore manualmente ogni volta che cambio controller, ma non mi fido molto di quella soluzione molto, come dimenticare di impostare il valore potrebbe rovinare tutto. Inoltre, il valore potrebbe in qualche modo sfuggire alla sincronizzazione con il controller attuale presentato. Più affidabile, penso, per testare direttamente la classe. – TraxusIV

+0

Per chiarire, la motivazione originale alla base di questo era quella di essere in grado di scorrere una serie di controller di visualizzazione presentati quando un pulsante 'ciclo' viene premuto dall'utente. Se il controllore di classe A è attualmente presentato, passa a B. Se viene presentato B, passa a C, ecc. – TraxusIV

risposta

9

Come descritto in questo forum post si sarebbe meglio applicare il Liskov Substitution Principle e mettere la logica <do stuff> nella classe reale, e quindi chiamare un metodo condiviso da una superclasse tutte queste classi ereditano (o un protocollo in Obj-C, se si stiamo progettando di avere questa logica condivisa tra classi completamente diverse).

Questo incapsula tutta la logica in ogni implementazione/sottoclasse senza che una classe di livello superiore debba preoccuparsi di ogni singola possibile implementazione che si possa avere. Ciò migliora la manutenibilità ed è più comune nella programmazione orientata agli oggetti rispetto alla semplice programmazione procedurale precedente.

+0

+1 Ottima risposta. Ho la sensazione che la mentalità originale dell'OP fosse per un controller di visualizzazione rispondere in un certo modo a seconda della classe dell'oggetto. C'è un momento in cui tale approccio è ammissibile, o rispetteresti sempre il principio di sostituzione? –

+1

Grazie, 'rispondi in un certo modo' Penso che tu voglia che la classe decida cosa fare e non un controllore onnipotente. Probabilmente userò solo un interruttore per ciò che è inteso qui - passando da valori primitivi. Non ricordo di aver fatto affidamento su di esso pesantemente però :) –

+0

L'intento è in realtà essere in grado di passare da un tipo di controllo all'altro. Se è di tipo A, allora presenta il tipo B. Se è di tipo B, quindi presenta il tipo C, ecc. Quindi a mio avviso una cosa del genere appartiene davvero alla classe del controller master piuttosto che alla sottoclasse. – TraxusIV

0

Questo non è possibile. Devi usare if-elseif dichiarazione come questa

if ([currentSubViewController isMembefOrClass:[UITableViewController class]]) 
{ 
    <do stuff> 
} else if ([currentSubViewController isMemberOfClass:[UICollectionViewController class]]) { 

} 

avviso che uso isMemberOfClass: per simulare ciò che switch-case dichiarazione farà. Ma nella maggior parte dei casi si desidera utilizzare isKindOfClass:

1

L'istruzione switch funziona solo con tipi di interi. Hai bisogno di un grande blocco if-else.

Se si desidera forzare un'istruzione switch, è possibile elaborare qualcosa utilizzando una serie di classi fisse e basare lo switch fuori dalla posizione dell'indice della classe che si sta verificando. Ma per la leggibilità nelle istruzioni caso, è necessario definire un insieme di costanti che rappresentano la posizione dell'indice di ogni classe. Questo è un sacco di lavoro e codice da mantenere solo per evitare e il blocco if-else.

0

È possibile utilizzare un dizionario letterale.

((void(^)())@{ 
NSStringFromClass([UITableViewController class]) : [^{ 
    // stuff 
} copy], 
NSStringFromClass([UICollectionViewController class]) : [^{ 
    // stuff 
} copy] 
}[NSStringFromClass([currentSubViewController class])])(); 

NOTA: Questo è solo per divertimento. Per favore, non prenderlo come un suggerimento serio.

Utilizzare seriamente la risposta @AramKocharyan.

+0

perché non usare la classe direttamente? –

+0

'Class' non è conforme a' NSCopying'. –

+0

hai ragione, ma questo è anche vero '[[NSObject class] respondsToSelector: @selector (copyWithZone :)]' –

0

Un modo è creare una struttura dati che rappresenti le classi che si interessano ai valori in un enum. Questo sarà un sacco di codice piastra della caldaia.

Sfortunatamente, Objective-C non ha linguaggi condizionali orientati agli oggetti come il Ruby come switch. Ha solo la dichiarazione C switch. A case nell'istruzione C switch richiede una costante intera ed è ciò che impedisce ulteriori approcci dinamici utilizzando le istruzioni C switch. Il tipo C enum funziona anche con le costanti. Ciò significa che nessuno può essere generato in fase di runtime, ma potrebbe essere in fase di compilazione.

C enumerazioni e istruzioni di commutazione funzionano bene insieme ma non così tanto caldo per gli oggetti.

Quindi, potrebbe essere meglio fare composizioni if-else composte per fare i tuoi confronti qui.

Problemi correlati