Objective-C Primer 番外編 10.オブジェクト〜最終回〜

最新更新日時6/1/23:55

サンプルコードのSeito.mで一部不具合がありましたので新しいものに変えました。6/1/23:55

新しいサンプルコードは seito3.zip からダウンロードできます。

実行方法
ターミナルでの実行方法は次の通りです。
cd Desktop/seito3
vivacocoaファルダに移動されていた場合は
cd Desktop/vivacocoa/seito3
続けて
cc main.m Seito.m -o seito -framework Foundation
これで seito という実行ファイル名でコンパイルされます、実行は
./seito
とコマンドして実行します。

「名前」は先頭が空白文字で始まらない限りなんでも受け入れることにしました。
「点数」は0から100までの数字のみを受け付けます。
「評価」は自動でされるようにしました。
もう1度試してみたい場合は最後に y (イエス)を、終了する場合は n (ノー)をタイプしてください。






Seito.h
d0122908_20241084.gif

1行目で NSObject クラスのヘッダファイルを、2行目から5行目ではそれぞれの関数のヘッダファイルを読み込んでいます。なお、関数についてはすべてC言語の関数です。

7行目。記号定数を使って MOJISUU を100と決めています。これは文字を読む込み時(数字も文字です)に何文字まで読み込むかを決めるのに使っています。MOJISUUという記号定数はプログラムの中で何箇所も出てきていますのでここの数字を変えれば MOJISUU と記入されている箇所の数字が一度にすべて変えることができます。

9行目。クラス名はこのように大文字で始める習慣になっています。SeitoクラスはNSObjectクラスをスーパークラスにしています。自作クラスの場合、ほとんどはNSObjectがスーパークラスになります。

11行目。char型を100要素(100個)持った配列、つまり文字列です。
12行目。int型。整数のみを入れることのできる型です。
13行目。char型の変数を宣言しています。つまり文字列ではなくて文字です。

16行目から21行目。
それぞれの変数に対して、「set変数名」と「変数名」というメソッドを宣言しています。変数の値を設定するメソッドを「setHensuu」、変数の値を取得するメソッドを「henssuu」と命名するのがAppleの指針となっています。
 この命名方法についてもう少し説明を加えると、
  1.クラス名は大文字で始める
  2.変数やメソッド名は小文字で始める
  3.複数の単語で構成される名前は2つ目以降の単語の始まりを大文字にする
  4.アクセッサメソッド(変数の値を設定・取得するメソッド)は「set変数名」と「変数名」にする
 なお、CおよびObjective-Cではクラス名・変数名・関数名・メソッド名にはアルファベットと数字とアンダースコア「_」が使えます。しかし名前の始めに数字を使うことはできません。またアンダースコアで始まる名前は言語の仕様あるいは処理系の仕様として使われている可能性が高いので通常は使わないようにします。

20行目。この setHyouka はプログラムの中から直接呼び出されることがないので不必要な気がしますが、1つの変数に対して設定と取得の2つメソッドを揃えておくほうがプログラムは読みやすくなります。






Seito.m
d0122908_2338165.gif

このサンプルコードの一部の不具合を修正いたしました。6/1/23:55
1行目で自作クラス Seito のヘッダファイルを読み込み、3行目以降で Seito クラスのメソッドを実装しています。

setNamae メソッド(5行目から18行目)
8行目。全角スペースで初期化された space という文字列変数を宣言しています。全角文字はchar型を2つ必要としますのでこの場合は複数のchar型つまりchar型の配列となります。
9行目。strlen 関数は引数内の文字列の文字数を返します。ここでは setNamae メソッドの引数として渡ってきた string 文字列の文字数から1文字分マイナスした文字数を int 型変数 leng に代入しています。
11行目。strncpy 関数は、第1引数に第2引数の第3引数番目までの文字列をコピーします。第1引数と第2引数は文字列。第3引数は整数値となります。この例では空の文字列ssに、setNamaeメソッドの引数として渡された文字列stringの始めの2文字をコピーしています。
12行目。if (isspace(string[0]) || !(strcmp(ss, space)))
isspace 関数は引数の中の文字が半角スペースやタブの場合に真を返します。string[0]で string 文字列の最初の文字を取り出しています。つまり string 文字列の最初の文字が半角スペースかタブなら真を返すことになります。
 strcmp 関数は第1引数 > 第2引数の場合は正を、第1引数 == 第2引数の場合は0を、第1引数 < 第2引数の場合は負を返します。ここでは文字列 ss つまり文字列 string の最初から2文字(半角で2文字)と文字列 space とを比べています。ss と space が同じ場合は0を返します。0はとして評価されます。つまり10行目のif文では isspace 関数が真なら string 文字列の先頭は半角スペースかタブということになります。あるいは strcmp 関数が0を返せば string 文字列の先頭が全角スペースということになります。0は「偽」として評価されますので !(strcmp(ss, space))と条件式の先頭で「!」を使って返り値を打ち消しています。つまり「偽」なら「真」という意味になります。この2つの式のどちらかが「真」であれば続く13行目に進み NO を返してこのメソッドを終了します。もし12行目のif文に該当しなければ15行目に進みます。
!(strcmp(ss, space)) は strcmp(ss, space) == 0 としたほうがコードが読みやすくて良いかもしれません。

15行目。strncpy(namae, string, leng);
strncpy 関数は2度目の登場です。第1引数namae文字列に第2引数string文字列の第3引数leng番目までの文字列をコピーします。9行目でlengの値を決めるのにstrlen(string)からマイナス1としているのは string 文字列の最後にReturn(改行)が入っているのでそれを削除するためです。これで最後の改行を含まない文字列が namae インスタンス変数に代入(コピー)されます。
16行目。そして namae 文字列変数の leng 番要素に文字列の終わりを表す 0 を代入しています。strcpy および strncpy 関数では、例えば10文字の文字列に6文字の文字列をコピーした場合に前の残りの4文字はそのまま残ってしまいます。したがって文字列の終わりを示す0を欲しい文字列の最後に入れておく必要があります。文字列配列の要素番号は0から始まっていますので leng 番目の要素はすでに名前として登録しておきたい文字数の次の要素ということになります。0を代入した要素以降の要素に仮に文字データが残っていてもそれは無視されます。

setTensuu メソッド(24行目から48行目)
28行目。val = atoi(string);
atoi 関数は引数の中の文字列(この例の場合は string )を整数値に変換します。整数値に変換できない文字列の場合は 0 を返します。この例では返された値を val (int 型変数)に代入しています。
30行目。if (val)
val は整数値です。整数値は0だけが「偽」と評価され、そのほかの整数値は「真」と評価されます。この if 文では「0以外なら」という意味になります。
if (val != 0) としたほうがコードが読みやすくて良いかもしれません。

0以外であれば31行目に進み「val が 0以上でかつ100以下」ならインスタンス変数 tensuu に val の値が代入されます。それ以外の数値の場合はtensuuに値が代入されることなく34行目で NO を返してこのメソッドを終了します。
36行目からの else 句は val が 0 だった場合の処理を行っています。val が 0 の場合は数値としての 0 の場合と「数値に変換できなかった場合の0」の2通りがあります。その2つを選り分けているわけですが、ここの詳しい説明は省略します。
46行目。[self setHyouka:tensuu];
入力された数値が0から100までの正しい数値だった場合にのみこの行が実行されます。このメッセージ式の左側の self はこのメソッドが属しているオブジェクトそのものを指します。すなわち「このオブジェクトのsetHyouka メソッドへインスタンス変数 tensuu の値を引数として呼び出す」ことを行っています。そして47行目で YES を返してこのメソッドを終了しています。

setHyouka メソッド(54行目から66行目)
まず56行目で seiseki が80点以上の場合に hyouka へ A を代入しています。
次に58行目で seiseki が70点以上の場合に hyouka へ B を代入しています。この時点ですでに80点以上の数値の場合の処理は終っていますので、おのずと点数が70点から79点の場合にのみ実行されることになります
60行目も同じ理屈で60点から69点の点数の場合にのみ hyouka へ C が代入されます。
62行目では、残った点数はすべて60点未満ということになりますので hyouka に D を代入しています。最後に65行目で YES を返していますが、この返り値は特に使われることはありません。他のメソッドとのバランスを考え、また将来拡張する時のことを考えて一応他のアクセッサメソッドと同じように BOOL 値を返すことにしているだけです。
 なおこのように何段階も条件検索するような構造になっている場合は、もしできるようなら該当する確率の高い条件から始めていくべきです。この例の if else 文でもそれぞれの条件式が該当した時点で if else 文の処理は終了します。確率の高い順番から条件を定めていけばそれだけ処理が早く済むことになります。

namae、tensuu、hyouka メソッドは、それぞれ同名のインスタンス変数の値を返すだけのメソッドです。






main.m
d0122908_2155662.gif

メインループ
12行目から45行目がこのプログラムのメインループになります。ユーザーが終了を選ばないかぎりプログラムが続くアプリケーションではこのようにメインループを設けます。今回はメインループを do-while 文にしましたが、一般的には while 文が用いられるのが普通です。
 メインループの中に14行目〜21行目、23行目〜29行目、39行目〜43行目の3つの do-while 文があります。

42行目。tolower 関数は引数の中の文字(英文字)を小文字に変換します。
引数の中が大文字の場合は小文字を、小文字の場合はそのまま小文字を返り値として返します。したがって「続けますか? y/n : 」と表示された場合、大文字で「Y」もしくは「N」とタイプしてもその文字を受け付けることができます。

6/1/23:55
[PR]
by vivacocoa | 2007-05-25 16:32


<< Objective-C Pri... Objective-C Pri... >>