Передайте тип универсальному расширению Swift или, в идеале, выведите его.

Скажи, что у тебя есть

 class Fancy:UIView

вы хотите найти все родственные Fancy представления. Нет проблем...

    for v:UIView in superview!.subviews
        {
        if let f = v as? Fancy
            { f.hungry = false }
        }

Итак, попробуйте расширение,

public extension UIView
    {
    internal func fancySiblings()->([Fancy])
        {
            return (self.superview!
                .subviews
                .filter { $0 != self }
                .flatMap { $0 as? Fancy }
                )
        }
    }

Круто, теперь ты можешь

    for f:Fancy in self.fancySiblings()
        { f.hungry = false }

Фантастический.

Но,

Как обобщить это расширение для работы с любым подтипом UIView?

В идеале, может ли расширение даже определить тип? Так же как и взять тип?

Итак, что-то вроде...

public extension UIView
    {
    internal func siblings<T>( something T )->([T])
        {
            return (self.superview!
                .subviews
                .filter { $0 != self }
                .flatMap { $0 as? T }
                )
        }

а потом можно было бы назвать это как-то так...

    for f in self.siblings(Fancy)
    for p in self.siblings(Prancy)
    for b in self.siblings(UIButton)

Как вы можете указать универсальному расширению тип, который нужно использовать?

Кажется, вы можете вывести это в обратном порядке,

public extension UIView
    {
    internal func incredible<T>()->([T])
        {
        return (self.superview!
         .subviews
         .filter { $0 != self }
         .flatMap { $0 as? T }
         )
        }


    for f:Fancy in self.incredible()

    for p:Prancy in self.incredible()

Что удивительно, но не работает по-другому.

Вы даже можете...

    self.siblings().forEach{
        (f:Fancy) in
        d.hasRingOn = false
        }

Поэтому я все еще хотел бы знать, как передать тип что-то вроде for f in self.siblings(Fancy) и, в идеале, даже вывести его.


person Fattie    schedule 15.05.2016    source источник
comment
Аналогичный вопрос: stackoverflow .com/questions/37216240/ (если вы думаете, что это не отвечает на ваш вопрос, ничего страшного, но основная проблема та же).   -  person Hamish    schedule 15.05.2016


Ответы (2)


Просто используйте .Type:

internal func siblings<T>( something : T.Type)->([T]) {
    ...
}

После этого for f in self.siblings(Fancy) должен работать точно так, как ожидалось.

Полный рабочий пример:

class Fancy : UIView {}

public extension UIView {
    internal func siblings<T>( _ : T.Type)->([T]) {
        return (self.superview!
            .subviews
            .filter { $0 != self }
            .flatMap { $0 as? T }
        )
    }
}

let superView = UIView()
let view = UIView()
superView.addSubview(view)
superView.addSubview(UIView())
superView.addSubview(Fancy())

print(view.siblings(Fancy))

Правильно выводит одно Fancy представление!


Чтобы обратиться к запрошенному дополнению для необязательного использования явного параметра типа или применения вывода типа компилятора. Вы можете создать второй метод в том же расширении

internal func siblings<T>()->([T]) {
    return siblings(T)
}

Таким образом, предоставление явного параметра типа вызывает первый метод, а его опускание потребует от вас сделать его выводным и вызовет вторую функцию, которая в терминах вызывает первую внутренне.


Или вы можете использовать гораздо более быстрый способ и сделать явный аргумент типа необязательным со значением по умолчанию nil. Это, что примечательно, приведет к выводу в случае пропуска аргумента типа:

// power extension, it provides both infered or stated typing
internal func siblings<T>(_ : T.Type? = nil) -> ([T]) {
    return (self.superview!
        .subviews
        .filter { $0 != self }
        .flatMap { $0 as? T }
        )
}

Это позволит вам вызывать метод либо через

for f in self.siblings(Fancy)

или даже

for f : Fancy in self.siblings()

Оба будут работать, определяя только одну функцию.

person luk2302    schedule 15.05.2016
comment
@JoeBlow да, ты действительно можешь. Я просто не хотел менять больше кода, чем необходимо;) - person luk2302; 15.05.2016
comment
@JoeBlow Вы можете сделать аргумент типа необязательным со значением по умолчанию nil (_: T.Type? = nil). Это позволит вам вызывать метод с типом или без него. Стандартный вывод должен работать как обычно. - person Hamish; 15.05.2016
comment
@ luk2302 Ты случайно не на детской площадке? Общеизвестно, что игровые площадки нестабильны ;) У меня это отлично работает в полном проекте. - person Hamish; 15.05.2016
comment
@originaluser2, конечно, я :D, и я знаю это, все равно смешно, когда это происходит. - person luk2302; 15.05.2016
comment
@JoeBlow Я включил второй метод для ответа на ваш запрос. Но это должно быть так. Пожалуйста, больше никаких запросов. Мы уходим от первоначального вопроса. - person luk2302; 15.05.2016
comment
Быстрый. Это позволяет вам потратить невероятно много времени на совершенствование невероятно короткого кода. :) - person Fattie; 15.05.2016
comment
Опубликовал ответ, не беспокоясь о передаче типа, с кратким объяснением, почему это не нужно. - person GetSwifty; 04.08.2016

Аналогичный ответ на то, что было сказано ранее, но немного более упорядоченный и без необходимости передавать что-либо или повторять подпредставления более одного раза:

extension UIView {
    internal func siblings<T: UIView>() -> [T] {
        return superview?.subviews.flatMap {return ($0 == self) ? nil : ($0 as? T) } ?? []
    }
}

или мои предпочтения с использованием опций:

internal func siblings<T: UIView>() -> [T]? {
        return superview?.subviews.flatMap {return ($0 == self) ? nil : $0 as? T } 
}

Пример использования:

class ExampleView: UIView {

    func getMatchingSiblings(){
        let foundSiblings: [ExampleView] = siblings()
    }

    //or with the for loop in the question:
    for item: ExampleView in siblings() {

    }
}

При работе с дженериками вам просто нужен один экземпляр универсального типа в сигнатуре метода. Поэтому, если у вас есть параметр или возвращаемый тип, который использует универсальный тип, вам не нужно передавать тип.

person GetSwifty    schedule 04.08.2016
comment
Также невероятно информативно. Я щелкнул вознаграждение за этот ответ а также - еще раз всем спасибо! - person Fattie; 06.08.2016