2016-06-16 2 views
5

У меня есть протокол «DifferentThings» и два класса, которые соответствуют ему, «ThingType1» и «ThingType2». Я поместил некоторые объекты этих двух типов классов в массив, содержащий «DifferentThings». Теперь я хочу просто взять все объекты из этого массива, которые относятся к типу класса «ThingType2», например. Как я могу это сделать?В Swift как я могу отфильтровать массив объектов, соответствующих протоколу по их классу?

Вот что я до сих пор:

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) 

ответ

6

Я хотел бы использовать flatMap вместо от filter здесь, чтобы обеспечить вам лучшую безопасность типов. Вы можете использовать условное нажатие, чтобы отфильтровать элементы, которые вы хотите, и общие элементы, чтобы сохранить информацию о типе. Это использует тот факт, что flatMap может отфильтровать nil результат функции преобразования.

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] 

Теперь массив вы получаете из вашей itemsMatchingType функции [ThingType1], если вы передаете в ThingType1, а не просто [VariousThings]. Таким образом, вам не придется иметь дело с уродливыми вынужденными понижениями позже по линии.

Если вы действительно хотите получить фантазии, вы можете также удалить аргумент типа и пусть Swift выводить типы отфильтровать с помощью явного типа аннотаций:

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

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

'.self' на самом деле не нужен. – vadian

+0

Nice one also =) –

+0

Хороший совет по карте и возврату T –

1

Вы можете использовать filter для этого:

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

Недостатком этого метода является что вы * знаете *, что результирующий массив имеет только элементы типа 'ThingType1', но если компилятор заинтересован, они просто соответствуют' DifferentTypes'. –

3

Вы могли бы использовать общий

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

Отлично, спасибо! –

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

Лучше, если вы сможете объяснить, что делает решение, а не представлять его автономно. Тогда другие смогут понять ваш ответ. – AlBlue

Смежные вопросы