|
|
1. オブジェクト
今回も懲りずにターミナルを使ったコマンドラインで Objective-C という言語にのみに焦点を当てて説明していくことになります。ご了承のほどよろしくお願いします。なお将来的にはこの learn ObjC 2.0 の簡易版で作った intro コマンドラインプログラムと learnObjC 2.0 正式版で作った book コマンドラインプログラムを GUI バージョンへと発展させる予定です。
準備
この「learn ObjC 2.0」では C言語の基礎が分かっていることが前提になっています。もし C言語をご存知でなければこのサイトの「learn C」を読んでください。できるだけ簡単に、そしてページ数も少なく説明したつもりです。またプログラムを作るには最低ソースコードを書くためのテキストエディタとそのソースコードをコンピューターの機械語に翻訳するコンパイラーというソフトが必要になります。ここでは Xcode 3のソースコードエディタとターミナルを使った実行環境で作業をすすめていきます。コンパイラは Xcode 3 をインストールすると同時にインストールされます。またこの「learn ObjC 2.0」で作るプログラムはウィンドウやボタンのあるGUIアプリケーションではありません。ターミナル上で起動するコマンドラインプログラムです。ターミナルは「アプリケーション」フォルダ内の「ユーティリティ」フォルダにインストールされています。Xcode 3はご自身でインストールしてください。インストール方法は「learn C」の
第1回
で詳しく説明しています。またターミナルのカスタム設定なども説明していますので必要な方はご覧になってください。
また、文字エンコーディングも UTF-8 に設定してください。たぶん Xcode もターミナルもデフォルトが UTF-8 になっているのではないかと思いますが次の方法で確認や設定をしておいてください。
まず Xcode を起動します。Xcode をインストールするとデスクトップ上の起動ディスクに Developer というフォルダができます。その中の Applications フォルダの中に Xcode があります。今後よく使うことになると思いますのでターミナルと合せて Dock に登録しておくと良いでしょう。
Xcode は最初に起動した時にだけ初期設定の画面が3つ出てきます。すべてデフォルトのままで「次へ」か「完了」を押していきます。そして Welcome to Xcode という画面が表示されます。これは起動するたびに毎回表示されますが、今は取りあえず閉じておいてください。
起動しましたら「Xcode」メニューから「環境設定...」を選んでください。テキスト編集タブで「デフォルトのファイルエンコーディング:」を次の図のように Unicode (UTF-8) に設定して OK ボタンを押します。もしデフォルトでこの UTF-8 が選ばれている場合はそのままクローズボタンなどで閉じて頂いて結構です。
図:Xcode 環境設定
次にターミナルも一応起動して「ターミナル」メニューから「環境設定...」を開いて「設定」画面の「詳細」タブで「文字エンコーディング:」を Uicode (UTF-8) にしてください。
図:ターミナル 環境設定
Hello World を超えて
プログラミング学習では最初に「Hello world!」と表示されるプログラムを作るのが決まりになっているみたいです。UNIX のコンソールや Mac OS X のターミナルではプログラムを起動すると「Hello world!」という文字列が表示されてそのままプログラムは終了します。GUIアプリケーションではプログラムを起動してからボタンをクリックすると「Hello world!」と文字列が表示されます。そして終了コマンドを選ぶまでアプリケーションが勝手に終了することはありません。この簡易版では、この Hello world! プログラムを拡張しながら Objective-C 2.0 の文法の説明をしていこうと思います。
作業
まずターミナルを起動してください。ターミナルを起動すると画面はまずあなたのホームフォルダからはじまります。 mkdir lite と入力エンターしてあなたのホームフォルダに lite というフォルダを作ります。次に cd lite で lite フォルダに移動します。そしてそこでまた mkdir lite1 と入力エンターして lite1 というフォルダを作ります。mkdir は make directory、cd は change directory の略でUNIXのコンソールで使用するコマンドと全く同じものです。インターネットで「UNIXコマンド」などで検索すると色々なコマンドを知ることができます。
次に Xcode 3を起動します。 Welcome to Xcode という画面は取りあえず閉じておいてください。「ファイル」メニューから「新規ファイル...」を選びます。次の画面で「プロジェクト内の空のファイル」を選び「次へ」を押します。ファイル名を「intro.m」にして保存場所の「選択...」ボタンを押します。あなたがさきほど作ったのホームフォルダの lite フォルダの中の lite1 フォルダを選んで「選択」ボタンを押します。元の画面に戻ったら「完了」ボタンを押してください。自動的にソースコードエディタが開くと思いますので次の intro.m を記述してください。C 言語のソースファイルの拡張子は .c でしたが Objectie-C のソースファイルの拡張子は .m になります。なお Objectie-C は C 言語の拡張版なので内容がまったくの C 言語のままのソースファイルに .m をつけてコンパイルしても問題はありません。最後に保存するのも忘れないでください。
intro.m
このサンプルコードは
lite1.zip からもダウンロードできます。コーディングが面倒であったり画面が見にくい時にお使いください。「lite1」というフォルダに入ってダウンロードされます。しかしできるだけご自身で書かれることをおすすめします。
実行方法
まずターミナルを起動してください。ターミナルはあなたのホームフォルダから始まります。cd lite/lite1 で lite1 フォルダに移動します(すでに lite1 フォルダに移動済みの場合はそのままで結構です)。次に ls コマンドで intro.m があることを確かめてください。なお ls -a とオプションで a を付けると隠しファイルも見えます。1つ上の階層に移動したい時には cd ../ とします。どこにいるのか分からなくなったときには pwd で現在の場所が表示されます。またどこにいる時でも cd とだけ入力するか、もしくは cd ~ (チルダ)と入力すると自分のホームフォルダへ戻れます。intro.m があることが確認できましたら次のコマンドで intro.m をコンパイルします。
gcc intro.m -o intro -framework Foundation -wall
ここで結構タイプミスをしてコンパイルできない場合があります。上記の文字列をコピーして使って頂いても結構です。余計なタグ文字は含まれていないようにしておきました。C言語の場合には
gcc filename.c -o 実行ファイル名
でコンパイルできましたが Objective-C の場合にはオプション -framework で使用するフレームワークを指定しなければなりません。なお上記の C言語のコンパイルコマンドのほうには余分なタグ文字が入っていますので直接コピーして使わないでください。
Objective-C のコンパイルで指定しているフレームワークは Foundation というもので Objective-Cでは必須のフレームワークです。 GUI のためのクラス以外の基本的なクラスのヘッダファイルが入っています。intro.m のコンパイルができましたら、
./intro
で実行します。
実行画面
まず「起動いたしました.」と表示されます。続けて「挨拶=1 編集=2 終了=3 」と表示されます。1 を選ぶと
Hello world !
と挨拶が返ってきます。
再び「挨拶=1 編集=2 終了=3 」と表示されますので 2 の「編集」を選びます。
「自己紹介文を入力してください.」と表示されます
My name is Takao Yamada. Nice to meet you!
などと入力してエンターキーを押します。このプログラムでは空白文字は文字列に含まれますが1行までしか入力できません。次の「挨拶=1 編集=2 終了=3 」で再び 1 を選びます。
自己紹介文が入力した通りに変更されています。
再び 2の「編集」を選び今度は日本語で自己紹介文を入力します。そして無事日本語でも自己紹介文が返ってくることを確認してください。
3 を選ぶと、
「お疲れさまでした.」と表示されて introプログラムは終了します。
なおこのプログラムでは 1 2 3 以外の文字が入力された場合は
「挨拶=1 編集=2 終了=3 」という文字列が繰り返されます。
0001 や 02 などはそれぞれ 1 や 2 と判断されます。
3abcde などは 3 と判断されてプログラムは終了します。
はじめてのオブジェクト
intro.m 1行目
#import <Foundation / Foundation.h> では Objective-C に (正確には Cocoa フレームワークに) はじめから用意されている関数やクラスのヘッダファイルを読み込んでいます (クラスについては後ほど説明します) 。フレームワークとは便利な関数やクラスが用意されているものの総称で Cocoa はこのフレークワークに当たります。Foundation.h は基礎的なクラスや関数のヘッダファイルをまとまて読む込むもので正確な数は分かりませんが約200弱のヘッダファイルをまとめて読み込むことができます。なお Objective-C では #include の代わりに #import でヘッダファイルを読み込むことになっています。2行目と3行目では C 言語のヘッダファイルも #import で読み込んでいます。
7行目〜30行目
この部分がオブジェクトになります。正確にはオブジェクトのうちクラスと呼ばれるものの宣言(定義)と実装を行っています。オブジェクトはこのようにまず定義や実装などを記述して設計図のようなものを作っておきます。そして実際に使う場合にはこの設計図(クラス)をもとにしてインスタンスと呼ばれるものを作って使います。クラスは読み込んだヘッダファイルの中にも便利なものが多数用意されています。ほとんどの場合この用意されているクラスを使うことになります。簡単なプログラムでは自分で作るクラスは1つか2つだと思います。
7行目 @interface ITModel : NSObject
まずクラスの宣言(定義)は @interface クラス名 : スーパークラス名 ではじまります。クラス名はアルファベットの大文字で始める決まりになっています。使える文字はアルファベットのみと考えてもらって結構です。複数の単語からなるクラス名の場合には MyClassA などと単語の始まりを大文字にあとは小文字にします。スーパークラスに自分のクラスの親クラスを指定するとそのその親クラスの機能(インスタンス変数とメソッド)をすべて継承することができ、その継承した機能はあらためて記述する必要はありません。Objective-C では必ず1つだけスーパークラスを指定しなければなりません。特に継承すべきクラスがない場合は今回のように NSObject を継承します。NSObject にはオブジェクトとして動作するための機能が搭載されています。Cocoaフレームワークに用意されているすべてのクラスはそのスーパークラスをたどっていけばこの NSObject に到達するように設計されています。そして NSObject にはスーパークラスはありません。このようなクラスのことをルートクラスと呼びます。
8行目〜10行目
ブロック文 { } の間に C 言語の構造体で言うところのメンバ変数を宣言します。型の違う複数の変数を宣言できます。Objective-C ではこの変数をインスタンス変数と呼びます。インスタンス変数はアルファベットの小文字ではじめます。複数の単語からなる場合には2番目以降の単語の最初の文字だけを大文字にします。そして C 言語の構造体のメンバ変数と大きく違う点は、インスタンス変数はオブジェクト外からはアクセスできません。同じオブジェクト(クラス)内からしかアクセスできません。
11行目〜12行目
learn C の最後で「オブジェクトは構造体にそれに関連した関数を付け足したもの」という簡潔かつ乱暴な説明をしましたが、この2行がその付け足す関数に当たります。C++ ではメンバ関数 (もしくは関数メンバ) と呼びますが Objective-C ではメソッドと呼びます。この2行はそのメソッドのプロトタイプを宣言(定義)しています。
- (void)setString : (NSString *)newString ;
先頭の - はインスタンスメソッドであることを表します。これに対して + ではじまるクラスメソッドというものもあります。この2つの違いについては次回説明いたします。次に返り値の型を ( ) 内に記述します。返り値がない場合は void とします。次にメソッド名をアルファベットの小文字で書きはじめます。複数の単語からなるメソッド名の場合は2番目以降の単語の最初の文字だけ大文字にします。そしてコロン : の後に引数を書きます。引数の前にはやはり ( ) 内に引数の型を記述します。ここでは引数の型として NSString という Cocoa フレームワークに最初から用意されている文字列を扱うクラスのポインターを指定しています。Objective-C ではすべてのオブジェクト(クラスとインスタンスの両方)をポインターで扱うことに決まっています。最後はセミコロン ; で終ります。プロトタイプはセミコロンで終るのと同じことです。なおこのメソッドを C 言語風に記述すれば、void setString (NSString * newString) ; となります。
- (NSString *)string ;
今度は NSString型のポインターを戻り値とする string という名前の引数をもたないメソッドです。C 言語風に記述すると NSString * string ; となります。ところでこの string メソッドですがメソッド名がインスタンス変数 string と同じです。Objective-C ではインスタンス変数名とメソッドが同じになっても問題はありません。というかインスタンス変数の値を取得するメソッド (これを getter と呼びます) はインスタンス変数と同じ名前にしなければなりません。そしてインスタンス変数の値を設定するメソッド (これを setter と呼びます) は setインスタンス変数名 としなければなりません。この場合インスタンス変数の最初の文字は大文字にします。このセッターとゲッターを合せてアクサセメソッドもしくは単にアクサセと呼びます。Objective-C のインンスタンス変数は外部オブジェクトからはアクセスできません。ですのでアクサセメソッドは必須となります。今回はアクサセメソッドしか宣言(定義)していませんがメソッド宣言の数に制限はありません。
13行目 @end
@interface ではじまったクラスの宣言(定義)部分はこの @end で終ります。このクラスの宣言部分は普通は クラス名 . h という名前で別ファイルとして保存します。
15行目 @implementation ITModel
この @implementation から30行目の @end までの間で先ほど宣言したメソッドが実際に行う作業を記述します。このことをメソッドの実装と呼びます。メソッド実装の記述は関数の記述と似ていますのでだいたいの見当は付くと思います。なおこの ITModel というクラス名は Model (データを表すプログラミング用語) に IT という prefix (接頭辞) を付けて命名しました。自作クラスにはこのように接頭辞をつける事が推奨されています。今回は intro から IT を接頭辞にしましたが通常は会社名やグループ名を接頭辞にすることが多いみたいです。Cocoa フレームワークのクラスに多く見られる NS という接頭辞は Objective-C 言語の前所有者である NextStep 社の略です。なお Objective-C 言語の現在の所有者は Apple 社です。
16行目〜21行目 - ( id ) init メソッド
このメソッドは @interface 部で宣言していませんでした。しかしスーパークラスの NSObject の中で宣言されています。このように継承によって獲得したメソッドは @interface 部でわざわざ宣言する必要はありません。またメソッドの内容を変更する必要もなければ @implementation (実装)部でも何も記述する必要はありません。しかし init メソッドの場合はインスタンス変数を初期化するという役目がありますので各クラスの実装部でメソッドの内容を書き換えるケースが多いです。このように自分より上位のクラス(スーパークラス・親クラス・ルートクラス)で宣言・実装されているメソッドを書き換えることを上書き (override ) と呼びます。init メソッドの上書きには一定のルールがあります。1つのヒナ型としてこのルールを守って記述するようにします。
18行目 self = [ super init ];
self は自分自身のオブジェクトを表すために Objective-C に最初から用意されている変数です。super はスーパークラスのオブジェクトを表すために Objective-C に最初から用意されている名前です。[ super init ] はメッセージ式と呼ばれるものです。メッセージ式については後ほど説明しますが、この式によってスーパークラスの init メソッドがルートクラスの NSObject に達するまで順番に呼び出されて各インスタンス変数が無事に初期化されることになります。そして NSObject の init メソッドでは isa と呼ばれる特殊な変数に自分自身を格納します。そしてそのアドレスを self に格納します。ここで大事なのは自分自身というのは最終的な NSObject のインスタンスのことではなく最初に呼び出した、この場合では ITModel のインスタンスであるということです。これによって self が自分自身を表すようになります。
19行目 if ( self != nil ) string = @"Hello world !
" ;
nil とは存在しないという意味です。if 文で「self が存在しないということではなければ (self が存在していれば)」string インスタンス変数に Hello world !
という NSString 文字列のポインターが代入されます。文字列の前に @ マークを付けると NSStrig 文字列になると言う簡易記法です。if 文に続く実行式が1つの場合にはブロック { } で囲む必要はありません。また囲んでも問題はありません。
20行目 return self;
当然のことながら返り値として自分自身を表す self を返します。なお init メソッドの冒頭で返り値として指定されている id 型とはオブジェクトであれば種類を問わずにそのポインターを表す型です。
22行目〜25行目 - (void)setString : (NSString *) newStrig ;
24行目の string = [ newString copy ] ; で引数として受け取った NSString の文字列 newString を複製してその複製のほうのアドレス(ポインター)を string インスタンス変数に代入しています。ここでも [ ] のメッセージ式が登場しますが後ほど説明します。
26行目〜29行目 - (NSString *) string ;
28行目の return string ; で string インスタンス変数のアドレス(ポインター)をそのまま返しています。
30行目 @end
15行目の @implementation から30行目の @end までを普通はクラス名 . m として別ファイルとして保存します。
メッセージ式
あるオブジェクトのメソッドを実行したい場合にはメッセージ式と呼ばれるものを使います。メッセージ式は
[ オブジェクト メソッド名 ]
という形をしています。左側の「オブジェクト」という部分はレシーバーとも呼ばれます。レシーバーにはインスタンスの格納された変数、結果としてインスタンスが返ってくる式、およびクラスが指定できます。右側のメソッド名の部分はセレクタとも呼ばれますが実際にはレシーバーのオブジェクトが実装しているメソッド名を記述します。ここで注意しなければならないのは左側のレシーバーがクラスならクラスメソッドを、レシーバーがインスタンスならインスタンスメソッドをセレクタとして指定しなければならない点です。
メッセージ式はネスト(入れ子)することができます。最も有名な形としては40行目の
model = [ [ ITModel alloc ] init ] ; でしょう。この式は、
[ ITModel alloc ] で ITModel クラスをインスタンス化して、そのインスタンスを
[ ITModelインスタンス init ] で初期化しています。ここでは string インスタンス変数に「Hello world !」が代入されているのでしたね。そして init メソッドは自分自身を返しますのでそれを model 変数に代入しています。
メッセージ式を C++ や Java などのメンバ関数呼び出し風に記述すると
ITModel->alloc->init もしくは ITModel.alloc.init となると思います。しかしこの風変わりな見かけよりももっと根本的な部分で Objective-C のメッセージ式は特異性を発揮しています。メッセージ式は C++ などの関数呼び出しとは違いコンパイル時にチェックされて決定されることはありません。プログラムの実行時に初めて呼びされます。従ってその時に間違いがあれば無視されるかエラーが起こります。C++ では間違いがあればコンパイル時にエラーがでます。このことは Objective-C で書かれたプログラムにかなりの柔軟性を与えますが、実行速度が少し遅いというデメリットもあります。これはかなり難しい部分の事になります。この入門編で理解できなくてもまったくOKです。ただしこれからも「メソッドの呼び出し」という表現を使っていきますが、正確には「メッセージの送信」だということは覚えておいてください。
また「オブジェクト(あるいはインスタンス)を代入する」もしくは「オブジェクト(あるいはインスタンス)を返す」という表現も今後使っていくと思いますが、Objective-C ではオブジェクトは常にポインターとしてやり取りされます。従って上記の文は正確には「オブジェクト(あるいはインスタンス)のポインターを代入する」もしくは「オブジェクト(あるいはインスタンス)のポインターを返す」という意味であるということも覚えておいてください。
オブジェクトの特徴 まとめ
かなり大雑把なまとめですが、次の3つがどのオブジェクト指向言語についても共通して言える部分ではないかと思います。
1.
型の違う複数の変数(データ)とそれに関連するメソッドや関数(これらをまとめてコードとも呼びます)がまとまったもの
2.
設計図に当たるクラスと呼ばれるものからインスタンスと呼ばれるものを作って使う。1つのクラスからいくつでもインスタンスは作れる。インスタンスとは「実体」という意味になります。
※ ただし Objective-C ではインスタンス化せずにクラスのまま使うこともできます。しかしインスタンス変数はインスタンス化しなければ使えません。他の言語のようにメンバ変数と呼ばずにわざわざインスタンス変数と呼んでいるのはこのためです
3.
継承 ( inheritance ) というシステムを使って既存のクラスに新たに必要となる変数やメソッドのみを追加して新しいクラスを作ることができる。結果として記述するコード数を減らすことができる。また体系的にまとめていくこともできる。
などではないかと思います。
お疲れさまでした。これで「learn ObjC Lite」の第1回目は終ります。
|
|
|