Приведение подкласса из базового класса, где подкласс имеет универсальный в Swift - PullRequest
0 голосов
/ 25 октября 2018

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

Ниже приведен пример того, что яозначает:

class Base {

}

class Next<T> : Base where T : UIView {
    var view: T
    init(view: T) {
        self.view = view
    }
}

let a: [Base] = [Next(view: UIImageView()), Next(view: UILabel())]
for item in a {
    if let _ = item as? Next {
        print("Hey!")
    }
}

Почему "Hey!" никогда не печатается?


РЕДАКТИРОВАТЬ:

"Hey!" печатается, если приведениечитает:

if let _ item as? Next<UIImageView> ...

, но только для случая класса UIImageView.

и

"Hey!" печатаются, если один из элементовв массиве a - это:

Next(view: UIView())

В идеале я не хотел бы знать, какой тип является универсальным при приведении типов, но я понимаю, что это невозможно.

Ответы [ 3 ]

0 голосов
/ 25 октября 2018

Когда я увидел ваш пример, я ожидал, что он потерпит неудачу во время компиляции.

Кажется, что если вы укажете конкретный базовый класс для вашего T (в данном случае UIView), то компилятор может сделать выводэтот класс в as или is заявлениях.Поэтому, когда вы набираете item as? Next, компилятор понимает item as? Next`, потому что UIView - это конкретный тип.

Это не будет работать, если вместо UIView вы будете использовать протокол.Кроме того, простое использование Next вместо Next<UIView> (или Next<concrete subclass of UIView>) приведет к ошибке компилятора вне оператора is или as.

0 голосов
/ 25 октября 2018

Здесь протоколы помогают.

вам нужен фиктивный протокол для подтверждения Next на него

и используйте этот фиктивный протокол для проверки типов ваших предметов.

Поэтому мы создаем фиктивный протокол подтверждения Next и используем этот протокол для сравнения items.

код будет примерно таким.

class Base {

}

class Next<T> : Base where T : UIView {
    var view: T
    init(view: T) {
        self.view = view
    }
}
protocol  MyType  {

}

extension Next: MyType {}

let a: [Base] = [Next(view: UILabel()), Next(view: UILabel())]
for item in a {
    if let _ = item as? MyType {
        print("Hey!")
    }
}

UIView - суперкласс для всех UIElements.

говоря, что это приведет к истине,

if let _ = UILabel() as? UIView {print("yes") }

Next не подтверждает UIView, а скорее требует чего-то, что подтверждает UIView, поэтомувы не можете использовать подводные лодки UIView, чтобы проверить, являются ли они Next, у следующего нет точного типа,

здесь мы используем фиктивный протокол выше!

0 голосов
/ 25 октября 2018

Общий Next<T> - это своего рода шаблон, который создает уникальные отдельные классы.Next<UIView> и Next<UIImageView> - это два совершенно не связанных типа.

Вы можете объединить их с помощью протокола:

class Base {

}

class Next<T> : Base where T : UIView {
    var view: T
    init(view: T) {
        self.view = view
    }
}

protocol NextProtocol { }

extension Next: NextProtocol { }

let a: [Base] = [Next(view: UIImageView()), Next(view: UILabel()), Base()]
for item in a {
    if item is NextProtocol {
        print("Hey!")
    } else {
        print("Only a Base")
    }
}

Вывод:

Hey!
Hey!
Only a Base

Определив протокол, такой как NextProcotol, которому соответствуют все классы, производные от Next<T>, вы можете ссылаться на них как на группу и отличать их от других классов, производных от Base.

Примечание: Чтобы проверить, относится ли item к типу, используйте is вместо проверки, работает ли условное приведение as?.

...