Swiftでのキャストについて、調べましたのでブログにまとめておきます。
環境:Xcode6 beta6
詳細は、”The Swift Programming Language”の”Type Casting”に記載されています。
検証は以下のクラスを用いて行いました。
protocol SomeProtocol { func protocolMethod() } class BaseClass : SomeProtocol{ func protocolMethod() { println("Protocol Method BaseClass") } } class SomeClass1 : BaseClass { func some1() { println("SomeClass1") } } class SomeClass2 : BaseClass { func some2() { println("SomeClass2") } } class OtherClass : SomeProtocol{ func protocolMethod() { println("Protocol Method OtherClass") } }
型チェック
Swiftでの型チェックはis演算子で行います。
var baseObjects:[AnyObject] = [ SomeClass1(), SomeClass1(), SomeClass2(), ] for obj in baseObjects { if obj is SomeClass1 { println("SomeClass1") } if obj is SomeClass2 { println("SomeClass2") } }
以下のように、チェック対象の変数の型が明らかな場合、Xcodeによる文法チェックでエラーが表示されます。
var intValue = 1 if intValue is Int { <-- ここでエラーが出る println("intValue is Int") }
var intValue:Int = 1 if intValue is Int { <-- ここでエラーが出る println("intValue is Int") }
ダウンキャスト
Swiftでのダウンキャストはas演算子で行います。
var baseObjects:[BaseClass] = [ SomeClass1(), SomeClass1(), SomeClass1(), ] for obj in baseObjects { let some1 = obj as SomeClass1 some1.some1() }
配列に格納されている型が同一である事がわかっていれば、以下のように短縮して記述できます。
var baseObjects:[BaseClass] = [ SomeClass1(), SomeClass1(), SomeClass1(), ] for obj in baseObjects as [SomeClass1] { obj.some1() }
ダウンキャストが可能かどうか不明な場合、as?演算子で行います。
var baseObjects:[BaseClass] = [ SomeClass1(), SomeClass1(), SomeClass2(), ] for obj in baseObjects { if let some1 = obj as? SomeClass1 { some1.some1() } if let some2 = obj as? SomeClass2 { some2.some2() } }
これがハマるポイントになるかどうかわかりませんが、上記の検証をしていた中で気づいた事を記載します。
Swiftの型推論はArray型にも適用されます。
その為、配列の型を指定しなかった場合、以下のような挙動になります。
・SomeClass1、SomeClass2の共通の親クラスであるBaseClass型になる。
var array = [ SomeClass1(), SomeClass2() ]
・配列に格納されているクラスに共通のクラスがないため、本来であればエラーになるのですが、FoundationフレームワークがimportされているとNSArrayとして扱われます。
(自動的にAnyObjectになってくれたらいいのに・・・)
var array = [ SomeClass1(), SomeClass2(), OtherClass() ]
このNSArray型に、Swiftのオブジェクトを格納していると、以下のコードでハングします。
(内部で methodSignatureForSelector がコールされているようで、そこでハングします)
println(\(array))
今のところ、下記いずれかの方法で回避できることを確認しています。
- NSArray型に格納するオブジェクトをNSObjectを継承したクラスにする
- 配列をAnyもしくはAnyObjectで宣言する
なお、上記の配列に格納されているオブジェクトはSomeProtocolを実装しています。
配列をSomeProtocol型にしたい場合は、以下のように記述します。
var array:[SomeProtocol] = [ SomeClass1(), SomeClass2(), OtherClass() ]
最後は配列の話になりましたが、この辺のノウハウが蓄積される事を願うばかりです。
この記事を書いた人
- アプリ開発チームで、iOSエンジニアやってます。 *'``・* 。 | `*。 ,。∩ * + (´・ω・`) *。+゚ `*。 ヽ、 つ *゚* `・+。*・' ゚⊃ +゚ ☆ ∪~ 。*゚ `・+。*・ ゚
この投稿者の最近の記事
- IT関連2018.04.05僕も育休取らしていただきます
- iOS2015.10.21年に1度の、Apple Developer Programの更新
- iOS2015.04.01無謀にも時計のアプリをAppleWatch対応で申請してみたよ
- iOS2015.02.27SpriteKitのSKShaderを試してみた【iOS8〜】