[for-loop] for-in 루프에서 유형 캐스팅

이 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

그러나 그것은 작동하지 않습니다.



답변

대한 스위프트 2 이상 및 :

스위프트 2는 추가 의 경우 패턴대한 더욱 쉽게하고 더 안전에 캐스트를 입력 할 수있는 루프 에 대한 루프 :

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

Swift 1.2 및 이전 버전 에서 할 수있는 것보다 이것이 왜 더 나은 가요? 때문에 경우 패턴 은 컬렉션에서 특정 유형을 선택할 수 있습니다. 찾고있는 유형과 만 일치하므로 배열에 혼합이 포함되어 있으면 특정 유형에서만 작동 할 수 있습니다.

예를 들면 :

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

산출:

Hello
World!

대한 스위프트 1.2 :

이 경우에는 캐스트 view.subviews가 아닌 button캐스트이므로 원하는 유형의 배열로 다운 캐스트해야합니다.

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

참고 : 기본 배열 유형이가 아닌 [AClass]경우 충돌이 발생합니다. 즉, 무엇 !에가 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
    }
}

대한 스위프트 1.1 및 이전 버전 :

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

참고 : 하위보기가 모든 유형이 아닌 경우에도 충돌이 발생합니다 AClass. 위에 나열된 안전한 방법은 이전 버전의 Swift에서도 작동합니다.


답변

이 옵션은 더 안전합니다.

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

또는 신속한 방법 :

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


답변

where절을 사용할 수도 있습니다.

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


답변

제공된 답변이 정확합니다. 추가로 추가하고 싶었습니다.

강제 캐스팅과 함께 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 루프를 사용합니다.

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

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


답변

vacawama가 제공 한 답변은 Swift 1.0에서 정확했습니다. 그리고 더 이상 Swift 2.0에서 작동하지 않습니다.

시도하면 다음과 유사한 오류가 발생합니다.

‘[AnyObject]’는 ‘[AClass]’로 변환 할 수 없습니다.

Swift 2.0에서는 다음과 같이 작성해야합니다.

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


답변

다음과 같이 캐스팅을 수행하고 동시에 안전 할 수 있습니다.

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

}


답변