2016-06-16 106 views
5

Ho un protocollo, "VariousThings" e due classi ad esso conformi, "ThingType1" e "ThingType2". Ho messo alcuni oggetti di questi due tipi di classi in un array contenente 'VariousThings'. Ora voglio solo prendere tutti gli oggetti da quell'array che sono del tipo di classe 'ThingType2' per esempio. Come posso fare questo?In Swift come posso filtrare una matrice di oggetti conformi a un protocollo dalla loro classe?

Ecco quello che ho finora:

protocol VariousThings: class { 

} 

class ThingType1: VariousThings { 

} 

class ThingType2: VariousThings { 

} 


let array: [VariousThings] = [ThingType1(), ThingType2()] 


func itemsMatchingType(type: VariousThings.Type) -> [VariousThings] { 
    return array.filter { variousThing in 
     return (variousThing.self === type) 
    } 
} 


let justThingTypes1: [VariousThings] = itemsMatchingType(ThingType1) 

risposta

6

userei flatMap invece di filter qui per darvi una migliore sicurezza del tipo. È possibile utilizzare un downcast condizionale per filtrare gli elementi che si desidera e i generici al fine di preservare le informazioni sul tipo. Questo sfrutta il fatto che flatMap può filtrare i risultati nil dalla funzione di trasformazione.

let array: [VariousThings] = [ThingType1(), ThingType2()]  

func itemsMatchingType<T:VariousThings>(_ type: T.Type) -> [T] { 
    return array.flatMap {$0 as? T} 
} 

let justThingTypes1 = itemsMatchingType(ThingType1.self) // of type [ThingType1] 

Ora la matrice si ottiene dalla vostra funzione itemsMatchingType è [ThingType1] se si passa in ThingType1, piuttosto che semplicemente [VariousThings]. In questo modo non dovrai più affrontare brutti discorsi forzati in seguito.

Se davvero si voleva ottenere l'immaginazione, si potrebbe anche rimuovere l'argomento di tipo e lasciare Swift inferire i tipi di filtrare attraverso un tipo di annotazione esplicita:

func itemsMatchingType<T:VariousThings>() -> [T] { 
    return array.flatMap {$0 as? T} 
} 

let justThingTypes1 : [ThingType1] = itemsMatchingType() 
+0

'.self' non è in realtà necessario. – vadian

+0

Nice one =) –

+0

Buon consiglio su flatmap e ritorno T –

1

È possibile utilizzare il filter per questo:

let justThingsTypes1 = array.filter { $0 is ThingType1 } 
+0

Lo svantaggio di questo metodo è che tu * sai * che l'array risultante ha solo elementi di tipo 'ThingType1', ma se il compilatore è interessato, si conformano semplicemente a' VariousTypes'. –

3

si potrebbe usare un generico

func itemsMatchingType<T : VariousThings>(type: T.Type) -> [VariousThings] { 
    return array.filter { $0 is T } 
} 
+0

Perfetto, grazie! –

0
let justThingTypes1: [VariousThings] = array.filter { 
    variousThing in 
    return Mirror(reflecting: variousThing).subjectType == ThingType1.self 
} 
+0

È meglio se puoi spiegare cosa fa la soluzione, piuttosto che presentarla come indipendente. Allora gli altri saranno in grado di capire la tua risposta. – AlBlue