前回は @interface 〜 @end と @implementation 〜 @end を使ってクラスの宣言をしました。クラスはオブジェクトの設計図のようなものです。この設計図(クラス)をもとにしてメモリー上にオブジェクトを配置します。この作業を実体化と呼び、実体化されたオブジェクトを
インスタンスと呼びます。
「クラスはこのままでは使えません」という箇所を削除しました。
今回のサンプルコードは前回と同じものです。
seito1m.zip からダウンロードすることもできます。
Objective-Cも main 関数からプログラムは始まります。
id 型
seito1.m
32行目
id 型はObjective-Cで追加された新しいデータ型です。
id 型にはオブジェクトであればどのオブジェクトでも入れる事ができます。
オブジェクト型とも呼ばれます。id 型として宣言される変数は実はポインターになりますが、そのことを意識する必要はほとんどありません。Objective-Cではオブジェクトをそのポインター(メモリ上のアドレスを表す数値)でやり取りしています。つまり「すべてのオブジェクトのやりとりはポインターで行う」と決めてしまっています。ですから非ポインターと区別する必要がなくなり、結果的にポインターということを特に意識する必要がなくなったわけです。Objective-Cではこのような言語的簡略化があちらこちらで行われています。
これ以上のポインターの説明をこの回ですることはやめます。もし図解などをする機会があれば第3回「データ型」で行いたいと思います。
ただしここで1つ覚えておかなければいけないことは、
「クラスを型としてその変数をポインターとして宣言できる」ということです。
第6回で構造体を型としてその変数を宣言しましたね。その中で構造体のポインター(ポインター変数)も宣言しました。これと同じことがクラスでもできます。今回の Seito クラスの例では、
Seito * sei;
と宣言します。構造体の場合とは違い
Seito sei;
と非ポインター型で宣言することはできません。
構造体では struct 構造体名 変数名 の順序でしたが、クラスの場合は単純なデータ型のように宣言することができます
この宣言方法の利点は、
1. すべてのオブジェクト(クラス)を入れることのできる id 型とは違い、その変数がどのクラスのオブジェクトであるかがコードを読んでいて分かりやすくなる。
2. コンパイル時に変数の型とそこに代入されるオブジェクトの型が一致しているか、あるいはその型(クラス)が存在しているかチェックされます。このチェックに通らなければエラーとなりコンパイルは中断されます。このことは静的チェックと呼ばれていて、コーディングミスを防ぐ上では重要なことです。
3. Cocoaに最初から用意されているクラス(オブジェクト)では、その返り値や引数がオブジェクトである場合にその型を表すのにこの
クラス名 * で記述されています。結局この記述の仕方を覚えておかないと用意されているクラスを読む時に苦労します。
なお、32行目では id 型の変数 sei を宣言していますが、この時点では変数 sei は何の実体も持っていません(指し示してはいません)。
メッセージ式
seito1.m
36行目
変数 sei に実体のあるオブジェクトを代入しています。
sei = [[Seito alloc] init];
と、1行で書かれていますが、これは
sei = [Seito alloc];
[sei init];
の2行を1行にまとめたものです。普通は最初のように1行にまとまて記述します。
この [ ] で囲まれた式(文)のことを
メッセージ式と呼びます。
これで、ここまでに出て来たObjective-C固有の記述方法は、
1. @interface〜@end、@implementation〜@end
2. メソッドの記述方法
3. id 型
4. そしてこのメッセージ式
となります。このメッセージ式の説明をする前に上の2行のメッセージ式の意味を一応説明しておきます。
sei = [Seito alloc];
Seito クラスを配置する場所をメモリー上に確保しています。つまりインスタンス化する準備をしているわけです。そしてこのメモリー上のアドレスをid型変数のseiに代入しています。
[sei init]
sei変数が指し示しているアドレスに存在するオブジェクトのインスタンスをあらかじめ決めておいた数値で初期化しています。
正確には init で初期化が終った時点でインスタンス化が終ったことになるらしいので、このような難しい説明になりました。
メッセージ式の説明
メッセージ式はオブジェクトのメソッドを呼び出す時に使います。
つまり前回の「オブジェクトを作る〜クラス〜」で作ったSeitoクラスのメソッドや、そのスーパークラスの NSObject で用意されているメソッドを呼び出す時に使います。記述は、
[オブジェクト メソッド]
とします。式の左を見て下さい「オブジェクト」となっています。前回に「クラスとインスタンスの両方をオブジェクトと呼ぶ」と説明しました。すなわち左には、このサンプルコードの Seito というクラスも、そしてそのクラスのインスタンスを表す sei という変数も記述できるということです。
メッセージ式の右側にはそのオブジェクトの呼び出したいメソッドを記述します。このメッセージ式の中のメソッドのことを
セレクタ と呼ぶこともあります。意味は同じで「該当するメソッドを呼び出す」ということです。
[Seito alloc]
Seito クラスでは alloc というメソッドは作っていませんでしたが、スーパークラスの NSObject の中に alloc というメソッドがあります。alloc はクラスのインスタンスをメモリ上に配置するメソッドで先頭に + の付くクラスメソッドです。
[sei init]
init は、インスタンスを初期化するメソッド。こちらも NSObject で宣言されているメソッドですが先頭が - ではじまるインスタンメソッドです。
ここも「初期化されないとインスタンス化されたことにならない」という説明とは少し違った説明になっていますが、このように説明したほうが分かりやすいのでこのままにしました。
上の2つのメソッドで先頭に + のつくクラスメソッドはクラスに対して使えるメソッドで。先頭に - のつくインスタンスメソッドはインスタンスに対して使えるメソッドだということが分かります。
アクセッサメソッド
seito1m
47行目・54行目
[sei setTensuu:]
57行目
[sei tensuu]
この2つのメソッドの setTensuu と tensuu は、インスタンス変数の tensuu の値を設定するメソッドと tensuu の値を取得するメソッドです。このようにインスタンス変数の値を設定・取得するメソッドのことを
アクセッサメソッドもしくは
アクセッサと呼びます。
Objective-Cではオブジェクト内の変数(インスタンス変数)に直接アクセスする方法は基本的にはないことになっています。
Objective-Cでは変数の数値の安全化を計るためにユーザーが入力する値に間違いがないかどうかをチェックするために必ずメソッドを通して値を設定・取得することになっています。このように内部のデータ構造を秘匿していくつかのインターフェース(メソッド)だけを公開することをオブジェクトの
隠蔽化もしくは
カプセル化と呼びます。
このデータの安全化とは、たとえば点数は0〜100という数字のみしか入力されたくなかったり、評価はA〜Dだけにして欲しい場合に、それ以外の数値が変数に代入されるのを防ぐということです。
またAppleではこのアクセッサメソッドの命名方法に指針を出しています。その指針に従わなくてもプログラムは正常に動きますが、コードの読みやすさ(可読性と言います)のためにその指針に従うほうが良いでしょう。
1. インスタンス変数は小文字で始める。 例:abcd
2. インスタンス変数の数値を設定するメソッドは、例:setAbcd とする
3. インスタンス変数の数値を取得するメソッドは、例:abcd とする
インスタンス変数の数値を取得するメソッドは、インスタンス変数名と同じになることに注意してください。
少しだけコード説明
37行目
[sei setTensuu:10]
インスタンス変数 tensuu に10を設定していますが、プログラム上はまったく意味がありません。これは続く do-while 文を記述する際に正常に動作したかどうかを確かめるために(正常に動作しなかった時には10とそのまま返ってきます)10という数字を設定しただけです。
この行を削除もしくはコメント化してもプログラムの動作にはまったく影響ありません。
39行目〜54行目
やっと必然性のある do-while 文が登場してきました。制御文1およびサンプルコードの uruu.m で登場した do-while 文は do-while 文にする必然性はまったくないものでした。
今回の do-while文の細かい説明は割愛させてもらいますが、50行目の if 文のなかに登場する isdigit( ) C言語関数は引数( )の中の「文字」が数字かどうかをチェックする関数です。引数が数字なら true 「真」を返します。
5/19/23:00