Подтвердить что ты не робот

Переходите к типу с общим расширением Swift или в идеале выведите его

Скажите, что у вас

 class Fancy:UIView

вы хотите найти все представления sibling 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), и, в идеале, даже вывести его также.

4b9b3361

Ответ 1

Просто используйте .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)
}

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


Или, вы можете использовать гораздо более быстрый способ и сделать явный аргумент типа необязательным по умолчанию 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()

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

Ответ 2

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

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() {

    }
}

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