Objective-Cでは、id型であらゆるオブジェクトを表現できます。また、前回紹介したNSArrayなどの配列は、あらゆる型のオブジェクトを要素として保持することができます。
これは柔軟なプログラミングを可能にする非常に便利な仕組みですが、あるオブジェクトが実際にはどういったクラスのインスタンスであるのかという、判定が必要になる場面もあります。
以下に、オブジェクトの情報を確認する方法を見てみましょう。
#import <Foundation/Foundation.h> |
main.m |
(1)のisMemberOfClass:メソッドは、そのオブジェクトがあるクラスのインスタンスであるかどうかを判定します。引数には、“あるクラス”を表すクラスオブジェクトを渡します。
クラスオブジェクトは、あるクラスの型としてのメタ情報を保持するオブジェクトです。上記の例では、NSObjectの静的メソッドであるclassメソッドで取得しています。クラスオブジェクト自身の型としてはid型を利用するか、または文字通りClassという型を利用します。以下にクラスオブジェクトの生成方法を示します。
Class cls1 = [TestCls class]; // 静的メソッドで |
(2)のisKindOfClass:メソッドは、そのオブジェクトがあるクラスのサブクラスかどうかを判定します。引数は判定の基準となるスーパークラスのクラスオブジェクトです。
(3)のconformsToProtocol:メソッドは、そのオブジェクトがあるプロトコルを採用しているかどうかを判定します。引数は、今度はプロトコルを表すProtocol型のオブジェクトです。プロトコルオブジェクトは、上記のように「@protocol(プロトコル)」で取得するほか、「NSProtocolFromString(@"ProtocolA")」のように文字列から取得する方法もあります。
(4)のrespondsToSelector:メソッドは、そのオブジェクトがあるメソッドを実装しているかどうかを判定します。instancesRespondToSelector:メソッドは、具体的なオブジェクトではなく、あるクラスが、あるメソッドを実装しているかを判定します。
“あるメソッド”を表現するためには、SEL型を利用します。Objective-Cでは、メッセージ式で利用されるメソッド名をセレクタとも呼びます。このセレクタを表現するための型がSEL型です。
セレクタオブジェクトは、上記例のように「@selector()」で取得するほか、「NSSelectorFromString(@"testMethod2:arg2:")」のように文字列から取得することもできます。
(5)のclassNameは、オブジェクトからクラス名を取得するメソッドです。
先ほど紹介したisMemberOfClassやclassNameのようにオブジェクトのクラス名を判定する場面では、注意しなければならないことが1つあります。それは、あるクラスのオブジェクトを生成したつもりでも、実はそのサブクラスのインスタンスが返される場合があるということです。
実装者側からは1つのクラス定義に見えても、内部で状況に応じて複数のサブクラスが使い分けられている場合があります。Objective-Cのこのような仕組みをクラスクラスタといいます。
クラスクラスタの代表的な例はFoundationのNSStringクラスです。以下のコードを実行してみましょう。
#import <Foundation/Foundation.h> |
main.m |
各文字列オブジェクトからclassNameメソッドでクラス名を取得してみると、「@"aiueo"」で生成したオブジェクトでは「NSCFString」が、stringByAppendingPathComponent:メソッドで生成したオブジェクトでは「NSPathStore2」が、それぞれ返されます。
これは、インスタンス生成時に利用されたイニシャライザやインスタンス生成メソッドによって、それぞれふさわしいサブクラスが選定され、そのインスタンスが返されているのです。これらのサブクラスは、実装者側には隠ぺいされており、通常は意識することはありません。
このような、クラスクラスタを構成するサブクラスのことをコンクリートクラスといいます。
なお、@"aiueo"という最もシンプルな方法で生成された文字列オブジェクトがNSStringではなくNSCFStringとなっているのには理由があります。
Mac OSには、Cocoaのほかに、旧OSとの互換性を維持したCarbonというフレームワークがあります。また、このCarbonの基本ライブラリ(CocoaのFoundationに該当するもの)としてCore Foundationというものがあります。
このCore Foundationの文字列クラスであるCFStringを、Cocoa のFoundationから利用できるようにラッピングしているのがNSCFStringクラスなのです。そして、NSCFStringをコンクリートクラスの1つとして、CocoaのNSStringのクラスクラスタが構成されているわけです。
このように、Objective-Cのクラス構成は内部的に少し複雑になっている場合があります。ただし、先ほども述べたようにクラスクラスタのコンクリートクラスは実装者側には隠ぺいされていますので、普段は意識する必要はありません(むしろ意識させないためにクラスクラスタのような仕組みがあるのです)。ですが、クラスの型を直接判定してロジックに反映させるような場面では、注意が必要になります。
Copyright © ITmedia, Inc. All Rights Reserved.