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〜】



