web-dev-qa-db-ja.com

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

しかし、どちらも機能しません。

100
Arbitur

Swift 2以降の場合:

Swift 2はcaseパターンforループに追加し、さらに簡単にしますforループでキャストする方が安全です:

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!

Swift 1.2の場合:

この場合は、buttonではなくview.subviewsをキャストしているため、目的の型の配列にダウンキャストする必要があります。

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
    }
}

Swift 1.1以前の場合:

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

注:サブビューがすべてAClassタイプではない場合、これもクラッシュします。上記の安全な方法は、Swiftの以前のバージョンでも機能します。

144
vacawama

このオプションはより安全です:

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

または迅速な方法:

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

where句も使用できます

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

Vacawamaから提供された答えは、Swift 1.0で正しかったです。 Swift 2.0では動作しなくなりました。

試みると、次のようなエラーが表示されます。

「[AnyObject]」は「[AClass]」に変換できません。

Swift 2.0では、次のように記述する必要があります。

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

提供された答えは正しいです。これを追加として追加したかっただけです。

フォースキャストで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]
    ...
}

もう1つの方法は、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 {
    // ...
}
0
T.Meyer