修正日: 09/03/10
練習問題15
バインドでCalcBMIみたいなのを作ってみよう! その3
今回は「アクセッサ」の話です。前回バインドされた値に反映させるためには、値を変更する際
- (void)setValue:(id)value forKey:(NSString *)key;
というメソッドを使うと説明しました。ちなみに値を取り出すためには
- (id)valueForKey:(NSString *)key;
というメソッドを使います。値のセットのメソッドと比較すれば簡単だと思います。これらのメソッドによって値の設定/取り出しが行われる際、暗黙のうちに実行されるメソッド、それがアクセッサメソッドです。値の取り出しのためのアクセッサが「ゲッタメソッド」、設定のためのアクセッサが「セッタメソッド」と呼ばれます。これらアクセッサメソッドのメソッド名はインスタンス変数の名前によって自動的に決まります。インスタンス変数がhogeだった場合、ゲッタは
- (id)hoge;
セッタは
- (void)setHoge:(id)pHoge;
となります。つまりゲッタは変数名そのもの、セッタはset+先頭を大文字にした変数名です。前回このメソッドを書かなくても正しく動いた事からもわかる通り、このメソッドが存在しなくても値の取り出しやセットはできます。渡された値に対し何らかの変換を行う(単位を変換するなど)、値のセットのタイミングをきっかけにして何らかの処理を実行する、などのためにこのメソッドをかく事が多いです。
なぜ突然これを説明し始めたかというと、これが将来的に役に立つから、というのはもちろんですが、このシステムを使ってCalcBMIを更に簡略化できるからです。練習問題14ではアクションメソッドを準備して各コントロールを接続する事で値の変化を関知し、BMIや体重を再計算していました。しかし値が変化するときセッタメソッドが呼ばれるのですから、セッタメソッドが呼ばれたタイミングで再計算をすれば良いということになります。たとえば体重の値が変更された場合、
- (void)setWeight:(float)pWeight
{
weight=pWeight;
[self calcBMI]; //BMIを再計算する
}
といった具合です。
ということでここで問題です。練習問題14で使ったアクションメソッドは全て破棄し、アクセッサを使って書き直してください。これ、バグ無しで一発でちゃんとしたアプリを作れたら相当頭良いです。
ところで
- (void)setWeight:(float)pWeight;
のメソッドを見て疑問に感じた方はなかなか鋭いです。前回「setValue:forKey:」のメソッドについて、「valueはオブジェクトをとる」と説明しました。また「setHoge:」も引き数はid型です。セッタの引き数はオブジェクトである必要があるのでしょうか?実はセッタとゲッタは適切な型を指定してあればあとは、プログラムの方で自動的に型を変換してくれるのです。セッタの引き数がfloatであればNSNumber型のオブジェクトを放り込んでも、自動的にfloat型に変換してセッタに渡してくれます。ゲッタの返り値をintで返してもvalueForKey:で取り出すと自動的にNSNumber型のオブジェクトとして出てきます。「1.3」というNSString型の文字列を放り込んでfloatとして取り出すこともできます(NSStringにはfloatValueというゲッタがありますしね)。もちろん普通の文章を渡してlongで取り出す、などという芸当はできないので、渡す時に正しい値が行くように注意する必要がありますが、特に数値に関しては型をあまり気にする必要はありません。