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

Типовое литье во внутреннем контуре

У меня есть этот цикл for-in:

for button in view.subviews {
}

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

Я пробовал это: for button in view.subviews as AClass

Но он не работает и дает мне ошибку: 'AClass' does not conform to protocol 'SequenceType'

И я попробовал это: for button:AClass in view.subviews

Но и это не работает.

4b9b3361

Ответ 1

Для Swift 2 и более поздних версий:

Swift 2 добавляет шаблоны case для циклов, что делает его еще проще и безопаснее вводить в цикл for:

for case let button as AClass in view.subviews {
    // do something with button
}

Почему это лучше, чем вы могли бы сделать в Swift 1.2 и раньше? Поскольку шаблоны case позволяют вам выбрать ваш тип из коллекции. Он соответствует типу, который вы ищете, поэтому, если ваш массив содержит смесь, вы можете работать только с определенным типом.

Например:

let array: [Any] = [1, 1.2, "Hello", true, [1, 2, 3], "World!"]
for case let str as String in array {
    print(str)
}

Вывод:

Hello
World!

Для Swift 1.2:

В этом случае вы выполняете view.subviews, а не button, поэтому вам нужно сжать его в массив нужного типа:

for button in view.subviews as! [AClass] {
    // do something with button
}

Примечание. Если тип базового массива не является [AClass], это приведет к сбою. Об этом говорит ! on as!. Если вы не уверены в типе, вы можете использовать условный листинг as? вместе с необязательным связыванием if let:

if let subviews = view.subviews as? [AClass] {
    // If we get here, then subviews is of type [AClass]
    for button in subviews {
        // do something with button
    }
}

Для Swift 1.1 и ранее:

for button in view.subviews as [AClass] {
    // do something with button
}

Примечание. Это также выйдет из строя, если subviews не все типа AClass. Указанный выше безопасный метод также работает с более ранними версиями Swift.

Ответ 2

Эта опция более безопасна:

for case let button as AClass in view.subviews {
}

или быстрым способом:

view.subviews
  .compactMap { $0 as AClass }
  .forEach { .... }

Ответ 3

Вы также можете использовать предложение where

for button in view.subviews where button is UIButton {
    ...
}

Ответ 4

Ответ, представленный vacawama, был правильным в Swift 1.0. И больше не работает с Swift 2.0.

Если вы попытаетесь, вы получите сообщение об ошибке, похожее на:

'[AnyObject]' не конвертируется в '[AClass]';

В Swift 2.0 вам нужно написать как:

for button in view.subviews as! [AClass]
{
}

Ответ 5

Предоставленные ответы верны, я просто хотел добавить это как дополнение.

При использовании цикла for с принудительным приведением код завершится сбоем (как уже упоминалось другими).

for button in view.subviews as! [AClass] {
    // do something with button
}

Но вместо использования предложения if

if let subviews = view.subviews as? [AClass] {
    // If we get here, then subviews is of type [AClass]
    ...
}

другой способ - использовать цикл while:

/* If you need the index: */
var iterator = view.subviews.enumerated().makeIterator()
while let (index, subview) = iterator.next() as? (Int, AClass) {
    // Use the subview
    // ...
}

/* If you don't need the index: */
var iterator = view.subviews.enumerated().makeIterator()
while let subview = iterator.next().element as? AClass {
    // Use the subview
    // ...
}

Что представляется более удобным, если некоторые элементы (но не все) массива могут иметь тип AClass.

Хотя на данный момент (начиная со Swift 5), я бы пошел на цикл для случая:

for case let (index, subview as AClass) in view.subviews.enumerated() {
    // ...
}

for case let subview as AClass in view.subviews {
    // ...
}

Ответ 6

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

for button in view.subviews.compactMap({ $0 as? AClass }) {

}