ホーム

トップ
準備
Become An Xcoder

練習問題0
練習問題1
練習問題2
練習問題3
練習問題4
練習問題5
練習問題6
練習問題7
練習問題8
練習問題9
練習問題10
練習問題11
練習問題12
練習問題13
練習問題14
練習問題15

C言語補習1
C言語補習2
C言語補習3

推薦図書
ブックマーク

最後に

掲示板

Cocoa Docs

自作ソフトいろいろ




修正日: 09/03/10  

練習問題15  

 解答編


 バグのないアプリを作ることができましたか?私がCalcBMIを作った時も一回はまりました。ぱっと考えると以下のような感じのコードになると思います。

- (void)setHeight:(float)pHeight
{
  height=pHeight;
  [self calcurateBMI];
}
- (void)setWeight:(float)pWeight
{
  weight=pWeight;
  [self calcurateBMI];
}
- (void)setBmi:(float)pBmi
{
  bmi=pBmi;
  [self calcurateWeight];
}

- (void)calcurateBMI
{
  float  aBmi=weight/(height/100)/(height/100);
  [self setValue:[NSNumber numberWithFloat:aBmi] forKey:@"bmi"];
}

- (void)calcurateWeight
{
  float  aWeight=bmi*(height/100)*(height/100);
  [self setValue:[NSNumber numberWithFloat:aWeight] forKey:@"weight"];
}

 しかしこれではアウトです。例えば体重を変化させたとき体重の数値が変わって「calcurateBMI」メソッドが呼び出されます。これは良いのですが、「calcurateBMI」メソッド内でbmiの値が変わり、「setBmi:」のセッタが呼び出されます。「setBmi:」は「calcurateWeight」を呼び出します。「calcurateWeight」は体重をセットします。体重が変化したので「calcurateBMI」が呼び出されて・・・無限ループです。すぐにクラッシュしてしまいます。対策はどうすれば良いでしょうか?「calcurateBMI」「calcurateWeight」メソッド内で「setValue:forKey:」を使うのをやめる?それでは体重を変化させてもウィンドウ上のBMIの数値が変化してくれません。よく考えてみてください。





一つの解決策です。セッタを以下のように書き換えます。

- (void)setHeight:(float)pHeight
{
  if(height!=pHeight)
  {
    height=pHeight;
    [self calcurateBMI];
  }
}
- (void)setWeight:(float)pWeight
{
  if(weight!=pWeight)
  {
    weight=pWeight;
    [self calcurateBMI];
  }
}
- (void)setBmi:(float)pBmi
{
  if(bmi!=pBmi)
  {
    bmi=pBmi;
    [self calcurateWeight];
  }
}

 どういう事でしょうか?見ての通り、「数値が変化していない時は再計算をしない」ように改造してあります。例えば体重を変化させたときBMIを計算してセットします。BMIがセットされたら今度は体重を計算してセットしようとするのですが、体重を元に計算されたBMIなのでそれを元に計算しても元の体重に戻るだけです。なので体重の数値が同じであればここで再計算はやめます。これで無限ループを断ち切ることができます。
 一つの問題は整数値の計算ではなく小数の出る計算なので、正確に同じ数値に戻らないかもしれない、という点ですが、よくはわかりませんがとりあえずこれで動きます。プログラムにもっと詳しい人なら偶然なのか必然なのかわかると思いますが、不幸にして私には判断できません。本当はそんな書き方をしてはいけないのですけどね。他にも無限ループを回避する方法があると思いますので考えてみてください。
 配布版のCalcBMIはこれとはまた別の方法で問題を回避しています。次回はその方法について勉強します。