2015-02-23 24 views
5

Diciamo che ho classe generica Bus:Controllare se ANYOBJECT è di tipo generico in Swift

class Bus<T> { 
    func doSomething() {} 
} 

e posso creare un'istanza di esso:

var myBus = Bus<String>() 

Ora ho una funzione che prende un parametro del AnyObject e verifica il suo tipo:

Il mio problema è che non riesco a vedere un modo per verificare se object è di tipo Bus ed eseguire la funzione doSomething() se è di tipo Bus. Qualsiasi aiuto sarebbe apprezzato.


Edit: protocolli, inoltre, non sembrano risolvere questo il modo in cui dovrebbero.

import Foundation 

@objc protocol BusProtocol { 
    func doSomething() -> Void 
} 

class Bus<T> : BusProtocol { 
    func doSomething() -> Void { 
     println("asdf") 
    } 
} 

func checkType(object: AnyObject) { 
    if let foo = object as? Bus<AnyObject> { 
     foo.doSomething() // no match 
    } 
    if let foo = object as? Bus<Any> { 
     foo.doSomething() // no match 
    } 
    if let foo = object as? Bus<String> { 
     foo.doSomething() // prints "asdf" 
    } 
    if let foo = object as? BusProtocol { 
     foo.doSomething() // SIGABRT -- -[SwiftObject doesNotRecognizeSelector:] 
    } 
} 

checkType(Bus<String>()) 
+1

L'esempio di modifica che utilizza '@ objc' non sembra segfault con Swift 1.2 - ma ti dà un errore (che era presumibilmente il problema precedente, gestito con meno garbo) che i metodi nelle classi generiche non possono essere' @ objc' (perché Objective-C non supporta i generici). Tuttavia, se si rilascia il qualificatore '@ objc' sul protocollo, funziona come sperato (di nuovo, usando Swift 1.2, che ha introdotto più funzionalità attorno ai protocolli e' as') –

risposta

0

Hai praticamente capito.

func checkType(object: AnyObject) { 
    if let foo = object as? Bus<AnyObject> { 
     print("Got here") 
    } else { 
     print("Fail") 
    } 
} 

let bus = Bus<String>() 
checkType(bus) // Fail 

let otherBus = Bus<AnyObject>() 
checkType(otherBus) // "Got Here" 

So che non è proprio quello che vuoi, ma mostra ciò di cui ha bisogno Swift.

+0

Non funziona, l'ho provato. Si gira 'Argomento per tipo generico 'T' non può essere dedotto' –

+0

Oh capisco cosa stai chiedendo ora. Hai bisogno di sapere che cosa è sul Bus stesso? Ti importa che tipo di Bus contiene? – jervine10

+1

Ho solo bisogno di controllare se l'oggetto è una sorta di 'Bus' ed essere in grado di eseguire' doSomething() 'se lo è. –

6

Il problema qui è il tuo pensiero di Bus come una cosa concreta. Davvero non lo è. Bus<String> è. Bus<Int> è troppo. Ma lo Bus non è, almeno non nello stesso senso. Hai bisogno di sapere cosa è T.

Davvero, ciò che si vuole è quello di scrivere qualcosa di simile:

func checkType<T>(object: AnyObject) { 
    if let foo = object as? Bus<T> { 
     println("Bus<T>") 
    } 
} 

Ma se si cerca di usarlo, si otterrà un errore:

// error: Argument for generic parameter 'T' could not be inferred. 
checkType(myBus) 

A differenza di altre lingue, non puoi scrivere checkType<String>(myBus). Ma quanto segue potrebbe fare quello che stai cercando:

func checkType<T>(object: AnyObject, T.Type) { 
    if let foo = object as? Bus<T> { 
     println("Bus<T>") 
    } 
} 

checkType(myBus,String.self) 

Questo risolve quello T è per qualsiasi Bus<T> e funziona correttamente.

Si potrebbe obiettare che non si desidera specificare cosa sia T. Tuttavia, questo porta alla domanda ... una volta che hai capito che object è una specie di Bus, che cosa hai intenzione di fare allora? Stai pianificando di chiamare metodi su di esso o passarlo come argomento ad altre funzioni? È probabile che ciò che stai cercando di ottenere possa essere fatto meglio con una funzione generica e vincoli di protocollo, piuttosto che usare AnyObject e trasmettere.

2

In swift 2.x è possibile utilizzare un protocollo per raggiungere questo obiettivo, come si è tentato senza errori:

protocol Busish { 
    func doSomething() -> Void 
} 

class Bus<T> : Busish { 
    func doSomething() { 
    print(self) 
    } 
} 

func with_any_bus(obj:AnyObject) { 
    if let b = obj as? Busish { 
    b.doSomething() 
    } 
} 

with_any_bus(Bus<Int>()); 
with_any_bus(Bus<String>()); 

uscita:

swiftblah.Bus<Swift.Int> 
swiftblah.Bus<Swift.String> 

Questo può o non può essere utile a voi in particolare, dal momento che sembra essere utilizzando 1.2 , ma forse qualcun altro che si imbatte in questa domanda lo troverà utile.

+0

Grazie per questo suggerimento. Sono stato in grado di scrivere un protocollo vuoto da utilizzare per verificare se una classe fosse la mia classe generica. Nessuna funzionalità, volevo solo un assegno. –

Problemi correlati