2009/11/30

Instantiating Objects

これまでクラスの宣言をして来たが、ここではクラスで使うオブジェクトの宣言をする。



ここで行う処理の事をinstantiatingという。(日本語直訳だと具体例を挙げる。また出たよこのindirectionみたいな要素。)
オブジェクトを具体的に示す(インスタンスを生成する)ためにその分メモリ領域を確保してそこに情報を格納する。
その確保する時には何らかの値を格納してメモリを初期化するのだが、その値はランダムな値ではなく一定の値が格納される事になっている。
そのメモリ確保(allocation)と初期化が済んだ状態の事でインスタンスの生成が可能になる。
生成したインスタンスの値は「instance variables」 といい、「ivars」と表記する事もある。

新しいオブジェクトを作るためにはまず、クラスにメッセージを送る必要がある。
これはOBJCの特徴で、クラスをオブジェクトのように扱い、メッセージを送る事ができる。この事に関する英文は読めなかった。。。


実際にコードの解説をしようと思う。
まず最初にmain()があり、以前のサンプルShapes-Procedualでは配列を用意していたのに対し今回はidの属性を持つオブジェクト(だが中身は配列)を宣言している。

shapes[0] = [Circle new];
このようにshapes[0]に対して[Circle new]というメッセージを送る事で図形ごとのオブジェクトを生成する。
さらにサンプルShapes-Procedualと違うところがある。それは図形の要素を、構造体で決められた値を使ってオブジェクトとして宣言しているところだ。
setBoundsのrect0は最初にShapeRectとして、の中でsetFillColorのkRedColorはShapeColorとしてそれぞれ構造体で宣言された値を忠実に使っている。


drawShapes (shapes, 3);
そんな発狂するような処理(訳そのまま抜粋)を終えてこのようなコードを記述するとdrawShapesファンクションが実行されて画像描写が行われる。(最後のカッコの値はshapesの値を3つ使うという意味でいいのだろうか。。。)

The implementation Section

クラスの実装部の説明。

@interfaceの記述はクラスのインタフェースの記述。
この部分はAPI(Application Programmig Interface)またはTLA(Three-Letter Acronym)とも呼ばれる。
それに対してクラス内のオブジェクトの実際の仕事を@implementationで記述している。


 
@implementation Circle
このようにクラス名を@implementationのあとに記述する事でコンパイラに「ここがCricleクラスの肝だぞ」と宣言する。ここでは変数を扱う事が合っても「:」を付ける必要は無い。
それ以降は具体的なメソッドの記述になるが、もちろん@interfaceで宣言したメソッドを記述できる。その際に宣言した順番と記述する順番は異なっても構わない。

setFillColor:
最初のメソッドの記述。@interfaceで宣言した通り「:」 付きで宣言をする。C言語の記述のようにここでは最後に「;」を付ける必要は無い。また、変数の名前も変わっても構わない。
この場合は内部でcという変数を使っているのでそのままにするとエラーになってしまう。

ただ、、、なぜここでわざわざcという変数を代入しているのかが分からない。。。
その次のsetBoundsメソッドでも同じような記述はあるのだが。。。


最後にdrawメソッドの記述。
ここではこれまでに宣言したboundやfillColorをコンソールに表示するだけ。
つまり変数を直接扱う事はしていないので、前述の通り「:」を付けないのだ。

OOP in Objective-C 2

昨日の続きから






- (void) setFillColor: (ShapeColor) fillColor;
ここでいう「setFillClor:」はメソッド名。(:も含む)
それ以降の記述は返り値とその型を示す。
fillColorはパラメータの名前。それをメソッドの本体の中でも使うことになるが、自分の好きな名前にできるのでとても便利。
 setBoundsメソッドでも同じことを言える。

メソッドそのものが変数を扱うならば「:」を付ける、扱わなければ付けない。コレ鉄則。

そして最後の@endで、コンパイラにCircleクラスの宣言の終了を告げる。

2009/11/29

Implementing Object Orientation

前回のプログラムを改良したものとして03.10 - Shapes-Objectを紹介。

まず1つ目の変更点はメソッドdrawShapesの中身だ。



ここで変わった事は第一に、コードが短くなっていることだ。わざわざ図形ごとの処理を分けなくてもいい方法になっている。

次に、メソッドの最初に宣言しているshapes[]だ。これはid型の配列なのだが、ここでいうid型というのはオブジェクトを宣言する際に用いる。オブジェクトを呼び出す事はCの構造体を扱う事と同じような事なので、構造体へのidはポインタの1つといえる。
この場合は図形の種類を決める構造体へのポインタになる。

3つ目に変わった事は、中心のループだ。
forの内部ではまずid shapes = shapes[i]という宣言をする。
ここでは配列shapesのポインタを得て、id型のオブジェクトshapeという変数にそれを代入する。それぞれshapes[0] は赤い円のクラスCircleへのポインタ、shapes[1] は緑の長方形のクラスRectangleへのポインタ、shapes[2] は青い楕円のクラスOblateSpheroidへのポインタとなる。
そして[shape draw]と表記することで、shapeというオブジェクトが drawというアクションを実行するようになる。
 OBJCでは、このようにアクションがオブジェクトを呼び出すことを”アクションがオブジェクトにメッセージを送信する”と表現する。

[shape draw]で行われる処理の手順は以下のように示すことができる。
1、shapeがどのようなクラスであるか参照する。
2、コード内のどこにdrawというファンクションがあるか調べる。
3、shapeに含まれるクラスの情報を使ってdrawを実行する。





 OOP in OBJC
次に、これらの処理を行うために準備する重要な要素について説明。
Interface:クラスの宣言。この要素を宣言することで先ほどのようにクラスCircleによってdrawというアクションが実行されるようになったりする。
Implement:Interfaceの実装部。今回のコードの中ではdrawからCircleにメッセージを送信されたときにどのような処理をするか記述している。



このコードはクラスCircleに関する宣言のみ行っている。
1行目:コンパイラに対してNSObject型のCircleという名前のクラスを作ることを宣言。
2、3行目:このクラスを形成するために必要な要素の宣言を行う。
最低限、ここまでの処理(クラスの作成、2つの要素の構成)でクラスの宣言は完了する。カッコを閉じることで宣言の終了をコンパイラに指示する。
ちなみに、クラス内で自作した新たな宣言のことをクラスのオブジェクトに対するインスタンス変数という。

以下はメソッド宣言と呼ばれるものになる。
こんな宣言をサポートしてるぞと言わんばかりに、その名前と返り値の型・名前を記述する。
OBJCのメソッドが返すことができる値として「int, float, char, ポインタ, オブジェクトの参照, 構造体」があげられる。

まずは最もシンプルな- (void) draw;について。
「-」がつくことで「これはOBJCのメソッドだぞ」という意味になる。特に返り値は持たない。





読み込み中
クリックでキャンセルします
画像が存在しません



読み込み中
クリックでキャンセルします
画像が存在しません


2009/11/25

Procedural Programming

Object-oriented programmming(以下OOP)においてIndirectionは重要な要素になっている。

最大の特徴はコードを呼び出すという事だ。

そこで、説明のために用いていたサンプルコード「03.08 Shapes-Procedural」の解説に入ろうと思う。



まず始めに 、プログラム内部で使う構造体をenum型の列挙で宣言する。
kCircle, kRectangle, kOblateSpheroidの3つはShapeTypeという要素、kRedColor, kGreenColor, kBlueColorの3つはShapeColorという要素に含まれる。また、このプログラムでは使わないが、kCircleには0、kOblateSperoidには1といった番号が構造体に含まれる順番にバックグラウンドでは割り振られている。

次に、ShapeRectという構造体にはint型のX, Y, width, heightが含まれる。
このShapeRectや最後のShapeという構造体を宣言する時にenum型にしなかったのは、ShapeType型のtypeという変数のように、その内部で属性を持つ変数を定義するためである。


コードの手順とは異なるが、次はmain関数内の説明。


初めに、 Shape型のshapesという変数を3つ用意する。
ShapeRect型のrect0という変数に対して4つの値を代入する。これは先ほど宣言したint型のX, Y, width, heightに代入される事になる。
Shape[0].type = kRectangleとなっているように、構造体型の変数に対して"."をつけることでその構造体の中身を参照する事ができる。この場合はShape[0].typeということでShapeType型のtypeを参照しており、enum型のShapeTypeの中からkRectangleを参照している。




同様の処理をして行くと、main関数の中からdrawShapesというメソッドに飛ぶ。
ここの2つの引数shapesと3はShape型の変数shapes[]とint型の変数countに代入される。
drawShapesでは選択されたshapes[i].typeの値によって定義されている図形3つ分の処理を行う。


 
shapes[i].type = kCircleだった場合はdrawCircleというメソッドで宣言されているShapeRect型の変数boundsにshapes[i].bounds(=0, 0, 10, 30)が、ShapeColor型の変数fillColorにshapes[i].fillcolor(=kRedcolor)が与えられる。
同様の処理をdrawRectangleとdrawOblateSperoidにも行う。
すると、各メソッドでは以下のようなコードを実行してコンソールに実行結果を表示するのだが、ここでさらにcolorNameというメソッドが呼び出されている。



ここでは用意されているShapeColor型のShapeColorに対してfillColorという値を与えている。ここで与えられたfillColorの値がkRedColorなら@"red"を返すというように、fillColorの名用によってその色の名前をNSString型として返す。
すると、コンソールにはこのような表示がされる。





このように、メソッドの中から違うメソッドを呼び出すと行った繰り返しをすることで コードを細分化し、各処理の内容を分かりやすく表記している。
それがIndirectionがもたらす最大の副産物ではないかと思う。

2009/11/21

先生への発表を通じて

発表を通して確認できたことを書こうと思う。

1(2009/10/26のエントリーより)
.hファイルで宣言しているstructure, symbolic, contants, function, prototypeについて。

実際の表記は
structs(構造体)
symbolic constants(記号定数)
function prototypes(関数原型)
というものだった。

構造体→1つのArrayで1種類の型しか宣言できないのに対し、1つの構造体では複数の型を宣言する事ができる。

記号定数→たとえばXcodeで「PI」と入力するとそれが円周率を意味するものになる。ここでいうPIが記号定数である。

関数原型→別名プロトタイプ宣言とも言い、あらかじめ使う関数を宣言することを言う。先日紹介したサンプルコードBOOL PartyでいうareIntsDifferentのようなもの。


2(同上)
precompiledヘッダファイルとは何か。

そもそもPrecompiledというのはコンパイル済みのという意味があるようで、そういうこれは既にコンパイルされたヘッダファイルという意味になる。マスタヘッダファイルがFoudation.hだとすれば、それに含まれるNSArray.hといったファイルがPrecompiledヘッダファイルという事になる。


2009/11/14

Indirection


今日はIndirectionについて書こうと思う。 
Learn Objective–C on the Macによると、「あなたは友人Aから本を借りていた。しかし、その友人は遠いところに住んでいるので返しに行くのが面倒。そんな時、隣人がAの住んでる近くまで出かけると言う。あなたは隣人にAの本を返すようにお願いした。それがIndirectionだ」と書いてあった。

つまり、、、人に頼んで自分の仕事をやらせるっていう解釈の良いのかな。
かなりの参考書を読んでみたが、それに該当するような表記が見当たらない。。。
次回のゼミの時に先生と相談しよう。


そんな中でのサンプルコード03.01 Count-1の解析。


 
プログラム自体は単純なforループで、コンソールに表示した回数を文字列で表示するもの。
ここでいう%dがキーポイントになるそうだ。ここでfor文の終了値を5から10に変えるとコンソールに表示される値も10になる。(最初のNSLogも表記を変えるために変更しておく。)
さらに、このfor文で使っている値をあらかじめint型で定義しておく事でも同じ事ができる。表示する部分は直接何も変更していないが、 それ以前の定義を変える事で出力結果も変わった。つまり、こんなとても簡単なプログラムの中でIndirectionを使っているといえるのだ。


次に、配列の文字列を読み込んでその文字数をカウントするプログラムを解析した。配列を定義してそこから文字列を読み込むものと、テキストファイルから読み込むものがあったが、今回はテキストファイルから読み込む方をピックアップしようと思う。

まずはテキストファイル。



このファイルがプロジェクトファイルと同じディレクトリに格納されてる。
内容を編集するとプログラムにも反映される。それを示すためにtomonariという内容を加えた。

そしてソースコードは以下の通り。



FILE *wordFile = fopen ("/tmp/words.txt", "r");で読み込みたいファイルを指定し、char[100]で100文字まで読み込める配列を宣言。
fgetsfgets(word, 100, wordFile)というwordFileから文字列を読み込んでwordに格納する処理をwhileの条件とし、その中では読み込んだ文字列数から1を引く処理をしている。それは、改行文字も1文字として認識されてしまうためだ。
そして最後に文字列とその文字列をコンソールに出力する。



こういった処理がIndirectionによるものだと言えるそうだ。
また、ファイル名をプログラム内で定義しないでも同じ処理が行えるものが紹介されていた。


変更した点は青く選択された部分だけ。
まず始めに、このプログラムは何を行うものか説明したいと思う。
argcの値が1の場合は「you need to provide a file name」というメッセージを表示し、そうでない場合はargv[1]に含まれる名前のファイルを開く処理を行う。それ以降は前のプログラムと同じものだ。

さて、ここで注目すべき点はargcとargv[1]という項目である。
この2つは最初のmain関数の定義の際に定義されているが、これらは何者なのだろうか。

これは前から気になっていたが放置していた項目の1つだ。
ネットで調べてみると、C系のプログラミング言語では共通してこの項目を使っているようで 、argvはプログラムが実行する際に読み込むファイルを格納するための配列、argcはその要素の個数を示すという。argv[0]にはプロジェクトを作成した際にデフォルトで実行ファイルの名前が入るが、それ以降については自分で設定できる。つまり、ここで読み込みたいテキストファイルを指定する事で先ほどのfopen()を使わないで済むのだ。

話を巻き戻すが、argc==1という事は配列argvに実行ファイル1つ以外格納されていないため、自分で設定しろという警告文を出していることになる。もしそうではなく何らかの項目が追加されているなら、argv[1]の内容が示すアドレスのファイルを開きなさい。といったポインタ的な考え型ができるのだ。

さっきからアドレスを指定だの何だの言っているが、それはXcodeで設定する事ができる。
右側のリストの「実行可能ファイル」を展開する事で表示される項目をダブルクリックする事で、次のようなウィンドウが表示される。


その中で引数のタブを選択して上の方の+マークをクリック。そして「/tmp/words.txt」を入力して作業は完了。
一般的な場合は分からないが、自分の場合はXcodeを再起動する事でこの設定が適用された。ちなみに「usr/share/dict/words」を追加してプログラム内で読み込み、表示させると辞書に含まれる全ての単語を読み込む事になり、エライ事になる。

この本ではこれ以降もIndirectionについて述べている。
さらに読み進めて行こうと思う。




2009/11/12

BOOL型について

C言語とOBJCではブールの表記が異なる。

C -> bool
OBJC -> BOOL

といっても大文字か小文字の違いのみ。Xcodeではどちらも使用できるが、返り値が異なる。ここが大きな違いと言えるのではないだろうか。

C ->「true」or「false
OBJC -> 「YES (1)」or「NO (0)

上記の通り、OBJCにおけるBOOLは水面下で「1」と「0」の返り値を扱っている。
BOOLではこういった8ビットの値を使っているが、8ビット以上の値が返ってくると「NO」をとして扱われる。
サンプルプログラム「BOOL  Party」を用いたBOOLの使い方の説明があった。

*コードをそのままコピペすると宣言部の山括弧がブログの仕様上、HTMLのタグとして認識されてしまうSHITな状況なのでコードは画像で貼付けた。

 
areIntsDiffent
ここではint型の2つの値 (thing1, thing2)を宣言、比較して同じならNOを、異なるならYESを返す。


NSString  *boolString (BOOL yesNo)
BOOL型で宣言されたyesNoに対して(BOOL型として)返って来た値がNOならばNOを、YESが返って来たらYES文字列として返す


int main...以降は主な処理。
BOOL 型でareTheyDifferentを宣言し、それに対して2つの値(5と5)をareIntsDifferentの処理にかける。この時点でareIntsDifferentにはBOOL型のNOが格納されている。それを文字列として表示するために、NSLogの内部でboolString(areTheyDifferent)とすることでBOOL型のNOをNSString型のNOにする。(boolString(NO)と同意)

同様の処理を 23と42の値で行うと、最終的にNSString型のYESが返ってくる。最期に0を返すことでプログラム終了。

といった具合だろーか。
ちなみに出力結果はコレ。



これでBOOLの使い方に付いては終了。

5と5は違う? NO
23と42は違う? YES

幼稚園児でも分かりますねこんなの。でも、英語の本読んでプログラムでこれできた時の爽快感と言ったら、、、くぅっ。

相変わらずペースはクソ遅いけど、順調に進んでます。
本のペースはと言いますと、次のステップとしてIndirectionについて読んでいます。日本語に訳すと、、、回り道でいいのかな。とにかく連呼してるんで、「Indirectionは、Indirection。」という風に解釈しちゃいます。問題は中身っす。
その一環としてmain (int argc, const char *argv[])についても理解しつつあります。(やっとかよ。)
詳細はまた明日!すみません、寝させてくだしあ。。。