2015-12-22 14 views
9

Come elencare tutte le classi che implementano un determinato protocollo in Swift?Come elencare tutte le classi conformi al protocollo in Swift?

Dire che abbiamo un esempio:

protocol Animal { 
    func speak() 
} 

class Cat:Animal { 
    func speak() { 
     print("meow") 
    } 
} 

class Dog: Animal { 
    func speak() { 
     print("Av Av!") 
    } 
} 

class Horse: Animal { 
    func speak() { 
     print("Hurrrr") 
    } 
} 

Ecco il mio attuale (non compilabile) approccio:

func getClassesImplementingProtocol(p: Protocol) -> [AnyClass] { 
    let classes = objc_getClassList() 
    var ret = [AnyClass]() 

    for cls in classes { 
     if class_conformsToProtocol(cls, p) { 
      ret.append(cls) 
     } 
    } 
    return ret 
} 

func objc_getClassList() -> [AnyClass] { 
    let expectedClassCount = objc_getClassList(nil, 0) 
    let allClasses = UnsafeMutablePointer<AnyClass?>.alloc(Int(expectedClassCount)) 
    let autoreleasingAllClasses = AutoreleasingUnsafeMutablePointer<AnyClass?>(allClasses) 
    let actualClassCount:Int32 = objc_getClassList(autoreleasingAllClasses, expectedClassCount) 

    var classes = [AnyClass]() 
    for i in 0 ..< actualClassCount { 
     if let currentClass: AnyClass = allClasses[Int(i)] { 
      classes.append(currentClass) 
     } 
    } 

    allClasses.dealloc(Int(expectedClassCount)) 

    return classes 
} 

Ma al momento della chiamata sia

getClassesImplementingProtocol(Animal.Protocol) o

getClassesImplementingProtocol(Animal) o

getClassesImplementingProtocol(Animal.self)

risultati in errore Xcode: non è possibile convertire valore di tipo (Animal.Protocol) .Type al tipo di argomento previsto 'protocollo'.

Qualcuno riesce a farlo funzionare?

+0

In quale riga si verifica l'errore? – luk2302

+0

Penso che questo potrebbe essere utile per te: http://stackoverflow.com/questions/28124684/swift-check-if-generic-type-conforms-to-protocol –

risposta

4

Dal momento che si sta utilizzando il runtime Objective-C per ottenere il tipo di introspezione è necessario aggiungere @objc al codice in questo modo:

@objc protocol Animal { 
    func speak() 
} 

class Cat:Animal { 
    @objc func speak() { 
    print("meow") 
    } 
} 

class Dog: Animal { 
    @objc func speak() { 
    print("Av Av!") 
    } 
} 

class Horse: Animal { 
    @objc func speak() { 
    print("Hurrrr") 
    } 
} 

Si noti che questo tipo di tipo introspezione potrebbe essere molto lento.

+0

Grazie Bruno, funziona. Per quanto riguarda le prestazioni, l'ho appena misurato: su iPad3 (che considero tra i dispositivi lenti) ci vogliono ca 115ms per una chiamata 'getClassesImplementingProtocol', mentre su iPhone6S ci vogliono 12ms. Per me, questo viene eseguito una volta all'avvio dell'app, quindi le prestazioni non rappresentano un problema critico. – mixtly87

+0

Non è lento come mi aspettavo, quindi è una buona cosa! Sono contento che abbia funzionato per te. – ColGraff

+1

C'è un modo per ottenere qualcosa di simile con le strutture? –