id型とは-動的結合の概念-
2015年1月31日:Objective-C
Objective-Cのコードを見ているとたまに「id」というデータ型が出てくることがよくあります。このidという型はオブジェクト用のデータ型で、オブジェクトを使う際によく使用します。idを使用することでプログラミングの柔軟性が上がり保守が容易になります。その一方でうまく使用しないとプログラム実行時のエラーになる恐れもあります。ここではこのidについてくわしく解説していきます。
idがない場合のオブジェクト生成
はじめにidがない場合にどのようにオブジェクトを生成するかの復習です。いま、以下の様なクラスTestClassがあったとします。
◯hファイル
@interface TestClass :NSObject{ } -(void)show; @end
◯mファイル
@implementation TestClass -(void)show { NSLog(@"This is TestClass!"); } @end
このクラスはひとつのメソッドshowがあり、このメソッドを使うとコンソールに
This is TestClass!
と表示されます。そして、このクラスをオブジェクト化して使用するには
TestClass *class=[TestClass alloc]; //メモリ確保 class=[class init]; //クラスの初期化 [class show];
とします。*classというアドレスにメモリを確保し、initによりクラスの初期化を行っています。そして、showを使ってコンソールに「This is TestClass!」と表示させています。
idを使った場合
さて、上記のようにオブジェクトを作ってもいいのですが、idを使ってオブジェクトをつくることもできます。その場合は以下のようにします。
id a=[TestClass alloc]; a=[a init]; [a show];
id型のデータaを作り、TestClassのメモリを確保しています。そして、initで初期化して、メソッドshowを実行しています。このようにidは様々なクラスに対応可能なデータ型ということができます。
idだとプログラム実行時におかしなことにならないか?
プログラミングをする際、idのような曖昧な定義だとおかしなことにならないかと不安になります。例えば、以下の様なクラスがあったとします。
◯hファイル
@interface TestClass :NSObject{ } -(void)show; @end @interface TestClass2 :NSObject{ } @end
◯mファイル
@implementation TestClass -(void)show { NSLog(@"This is TestClass!"); } @end @implementation TestClass2 @end
そして、以下のようにプログラムを実行したとします。
id a=[TestClass2 alloc]; a=[a init]; [a show];
このプログラムは明らかに間違いです。TestClass2にはshowというメソッドはありません。しかし、コンパイルすると成功してプログラムが起動します。ただし、コンソールに
-[TestClass2 show]: unrecognized selector sent to instance 0x100633390
というエラーが表示されます。showというメッセージが送られたけど、そんなメソッドはないようという内容です。
このようにidを使用するとプログラムに矛盾が生じる恐れがあります。
メソッドが使用可能かどうかをコンパイルでなく実行時に決定する方式を動的結合と呼びます。Objective-Cでは、オブジェクトをものとして扱います。そのため、どのようなオブジェクトにも好きなメッセージ(メソッドの命令)を送ることを可能としています。それが動的結合です。このようにオブジェクトに応じて適切なメソッドが選ばれる仕組みをポリモーフィズム(Polymorphism、多型性)といいます。
idだと柔軟なプログラミングが可能となる
以上の考察から、idを使うとプログラムが曖昧になりいいことがないように思えます。しかし、プログラムが曖昧になるということは柔軟なプログラミングが可能になるということも意味します。例えば、マウスが位置(x,y)を指し示してオブジェクトobjに原点(0,0)と(x,y)を元に図形を書かせる命令drawを送ったとします。もし、オブジェクトが円の場合は円、線の場合は線が書かれるようになります。この場合、コードは簡単で
[obj draw:x :y];
となります。もちろん、switch文などで分岐して動作を決定してもいいのですが、その場合、動作を変更する場合に動作に関わる部分をすべて変更する必要があります。一方、
idを使えば、クラスのみを修正すればいいのでプログラムの保守が楽になる
というメリットがあります。
著者:安井 真人(やすい まさと)
@yasui_masatoさんをフォロー