Objective-C 宣言プロパティとは.
以前、「インスタンス変数へアクセスする」の最後に書いたように、インスタンス変数へアクセスする方法として、「宣言プロパティ」を使う方法があります。
今回はその概念と定義の方法を解説し、次回で使い方を説明したいと思います。
プロパティーの概念
propertyとはもともと所有物とか、ものの性質といった意味があります。オブジェクト指向でいうオブジェクトの所有物、性質とは一体なんでしょうか。
プロパティーの概念を知るために、ちょっとした例を考えてみましょう。
例えば今、「人間」クラスのオブジェクトがあったとします。彼は「男性」で名前は「Nick」、星座は「天秤座」です。
これら全ての情報は、この彼にとって所有物、特徴になります。これがプロパティです。
外部のオブジェクトが彼について知りたければ、この情報を見ればいいのです。
しかし、今までのObjective-Cではこのような情報に外からなかなかアクセスできませんでした。なぜなら、これらの情報以外に、彼は自分の口座番号や仕事など、外部に知られたくない情報もたくさん持っているからです。
ですので、外部の人が彼について知りたければ、「この情報教えて!」と手紙を出して、返事を書いてもらうのがおおかたのケース。
とても仲がいいなら、彼に電話番号をもらって、直接なんでも聞くことができる人もいます。
前置きが長くなりましたが、これが今までのインスタンス変数へアクセスする方法です。
アクセサメソッドを介して、インスタンス変数に間接的にアクセスするか、もし、同じクラスのオブジェクトなら「->」演算子で直接インスタンス変数を参照できました。
しかし、Objective-C 2.0からは、プロパティという概念が追加されました。これはインスタンス変数へアクセスする、そのため専用の概念です。
先ほどの例で言うならば、名刺のようなものです。彼が他の人に知って貰いたい情報だけを載せた名刺を作り、それらの情報なら、どこで使ってもらっていいようにしたのです。
さて、概念的な話はこの辺りにしておいて、具体的にどのようなことがプログラムで行われているのか見てみましょう。まず、下のプログラムは人間クラスの定義です。
/* Human.h */ @interface Human : NSObject { BOOL man; NSString* name; int starSign; } -(BOOL)man; -(void)setMan:(BOOL)gen; -(NSString*)name; -(void)setName:(NSString*)newName; -(int)starSign; @end /* Human.m */ @implementation Human -(id)init { } -(BOOL)man // manのゲッタ { return man; } -(void)setMan:(BOOL)gen // manのセッタ { man = gen; } -(NSString*)name // nameのゲッタ { return name; } -(void)setName:(NSString*)newName // nameのセッタ { name = newName; } -(int)starSign // starSignのゲッタ { return starSign; } @end
実装部はイニシャライザとアクセサのみが書いてあります。インスタンス変数manとnameはゲッタとセッタが設定されており、このメソッドを通して読み書き可能という事がわかります。starSignは読み取り専用です。
例でいう「手紙を介して聞く」というのはこのアクセサを介して以下のように参照することです。
hisName = [obj name]; // "name"はここではメソッド名(ゲッタ) [obj setMan:NO]; // 彼を女にする(セッタ) herStarSign = [obj starSign]; // "starSign"はここではメソッド名(ゲッタ)
電話で直接聞くとは以下の様な「->」を使ったアクセスです。
myFriendName = obj->name; myFriendStar = obj->starSign;
さて、ここで言いたいことは、アクセサメソッドの面倒くささです。
たった3つのインスタンスをプロパティのように扱うためだけに、クラスの実装部ではかなりの行数を書かなければなりません。大きなプログラムになるといったいどれだけのアクセサを書かなければならないのでしょう。
これを解決してくれるのが宣言プロパティです。
宣言プロパティの使い方
宣言プロパティは、外部から参照できるものをプロパティとしてインタフェース部に定義することで、外部からも明らかにし、また、それと同時にそのプロパティに適したアクセサを自動で生成してくれる機能です。
この機能を使うと先ほどのプログラムがどのように変わるのか、早速見てみましょう。
/* Human.h */ @interface Human : NSObject { BOOL man; NSString* name; int starSign; } @property BOOL man; // @propertyでプロパティのタイプや名前を宣言 @property NSString* name; @property (readonly) int starSign; // readonlyは読み取り専用のプロパティーの宣言 @end /* Human.m */ @implementation Human @synthesize man; // @synthesizeでアクセサを生成 @synthesize name; @synthesize starSign; -(id)init { } @end
明らかにシンプルになりました。
コメントでも書いていますが、まず「@property」コンパイラ指示子について説明します。この8〜10行目で、前のプログラムの8〜12行目に当たるゲッタとセッタの宣言を済ませています。starSignのようにゲッタのみでいい場合は10行目のように”readonly”オプションを用いて宣言してやります。
実装部の方はどうでしょうか。こちらは更にシンプルになりました。前のプログラムの21行目〜44行目に当たる部分が、「@synthesize」コンパイラ指示子によって、17〜19行目とたったの3行になりました。
しかし、機能は全く同じです。@synthesizeは@propertyで宣言された変数名や、オプションを見ながら、自動的にアクセサを生成してくれます。(実際にプログラムを生成してくれるわけではありませんが、同じ機能を提供してくれます。)
例えばstarSignはreadonlyオプションがついていますので、@synthesizeはそれを判別し、ゲッタの機能だけを提供します。
他にどのようなオプションがあるのかや、独自でゲッタ、セッタを作る方法などは次回解説しますが、このように、宣言プロパティを使うことで、シンプルでわかりやすいプログラムを書くことができるのです。