Типовое литье во внутреннем контуре
У меня есть этот цикл 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
Но и это не работает.
Ответы
Ответ 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 }) {
}