Swiftいろいろ: [5] idとrespondsToSelector:
Objective-Cのプログラムでは、あるオブジェクトがメソッドを実装しているかどうかを動的に
Swiftの場合でも、
どうも、
こういう場合は、自分で呼びたいメソッドをプロトコル宣言(そのプロトコルを実装するクラスは作らなくてもいい)してやると良い。
もちろん、プロトコルの宣言は適切な位置に。
データ型がわかっているオブジェクトをわざわざ
なんて書かずに、
で済む。
古いObjective-CのAPIでは、(ブロックではなく)セレクタを引数にとるものが多いが、引数のデータ型が
ま、これから作るアプリではちゃんと
respondsToSelector:
メソッドで確認する場合がよくある。if( [anObject respondsToSelector:@selector(aMethod)] ) {
[anObject aMethod];
}
Swiftの場合でも、
NSObject
を継承していれば、respondsToSelector()
が使えない訳ではないが、あまりSwiftっぽい書き方ではない、ってことのようだ。由緒正しいSwift流の書き方は、optional chainingを使うってもの。let obj: AnyObject = anObject
obj.aMethod?()
AnyObject
は、Objective-Cでのid
に相当するので、どんなメソッドでも呼べる、ついでに、どんなメソッドでも@optional
扱いできる、って特典がある。(普通は@optional
じゃないメソッドに?
付けるとエラーになる。)んが、実際には、上のようなコードを実行(コンパイル)しようとすると、「AnyObject
型にはaMethod
なんてメソッドはありません」なんて意味のエラーになってしまう場合がある。どうも、
AnyObject
型から呼び出せるメソッドというのは、import
しているmodule内(自アプリを含む)のどっかのクラスかプロトコルで宣言されているものに限るらしい。(Objective-Cのid
は、どうだったっけか?)こういう場合は、自分で呼びたいメソッドをプロトコル宣言(そのプロトコルを実装するクラスは作らなくてもいい)してやると良い。
@objc protocol Optionals {
func aMethod()
}
//@optionalを付ける必要はないが、(beta3のSwiftでは)@objcがないと、うまくいかなかった。
もちろん、プロトコルの宣言は適切な位置に。
データ型がわかっているオブジェクトをわざわざ
AnyObject
型の変数(ってか、let
使ってたら定数というべきなのか?)に代入するなんてのが耐えられないって場合には、上記の方法は使えない。respondsToSelector()
メソッド使うしかなかろう。ちなみにSwiftの文字列定数は、自動的にSelector
型に変換可能なんで、if anObject.respondsToSelector(Selector("aMethod")) {
anObject.aMethod()
}
なんて書かずに、
if anObject.respondsToSelector("aMethod") {
anObject.aMethod()
}
で済む。
古いObjective-CのAPIでは、(ブロックではなく)セレクタを引数にとるものが多いが、引数のデータ型が
Selector
とわかっている場合も、文字列定数で大丈夫。ま、これから作るアプリではちゃんと
protocol
中で@optional
宣言して、そのプロトコルを実装したクラスで、optional chainingするってのが一番Swiftらしいんだろう。@objc
付けないと@optional
も使えないってのは美しくないが。