科学者向けのCocoa (part1):ハローブレーブニューワールド

英語チュートリアルの作成日:2006年10月17日
著者:Drew McCormack
翻訳:Ignacio Enriquez
Japanese Version of Drew's Tutorial.

Hi, I am Ignacio. I am an engineering master course student at Keio university - Japan. It's been arround 4 years since I began Mac programming and now besides my research on Computer Vision I am more like a iPhone programming guy, maybe. Last year in WWDC2009 I saw MacResearch and thought... Hey! I think I know that site!?.
Tutorials here are specially good and always wanted to contribute somehow. So, now with my English, Japanese and Programming skills I am able to translate this into japanese. Even-though this, my first official translation, still is kind of a beta version I will revise it more and I will do my best!

イグナチオと申します。慶応大学大学院理工学研究科、修士課程の学生です。Macプログラミングをやり始めて約4年経ちましたが、現在コンピュータビジョンの研究以外にiPhoneプログラミングをやっています。去年、WWDC2009でMacResearchのことを見て、「それ知ってる!」と思いました。

このサイトのチュートリアルが特に優れていて、昔から是非自分も何かしらの貢献をしたいと思っていました。そしてこの度、日本語と英語とプログラミングの知識で初めて翻訳にチャレンジしてみました!

以下はまだベータ版ですが、もう少しよくなると思います。頑張ります!
では、Drew McCormackのチュートリアルへ ...


Objective-Cに異議あり?

私は最近、MacResearchに入りましたが、サイトとそのコンテンツにどのような貢献ができるか決めなければなりませんでした。過去数年間で 定期的にCocoa開発のオンライン記事を書き、それらは最終的に出版されました。なので、Cocoaの知識に関しては問題ありませんでした。しかしながら、私は研究者(理論化学)でもあり FortranとCのような化石で日々プログラミングしています。そして、科学プログラミングのいくつかの短いコースも書いたことがあります。 私はまだ、科学者/研究者向けのCocoaのコースを開発していません。そして、幸運な連鎖により、私は現在、それができる立場にいます。

Cocoaを学ぶためには多くの場所が用意されています、(アップルのドキュメンテーションも)しかし科学者や科学者プログラミングに対象を絞った素材はありません。私の経験では、科学者は多くの時間を費やす余裕がありませんし、一昔前の技術にとらわれ、新しい概念を理解するのが困難な人は少なくありません。Cocoaの様な新しい技術を学ぶときには 科学者/研究者は力を抜く必要があります。なぜなら彼らの本業は研究/科学なのですから。

このチュートリアルのシリーズでは、Java、C#よりも むしろFortran、Cに慣れた人の嗜好に合う方法でアップルのフレームワークを紹介したいと思います。私は多くの科学的開発者にとって オブジェクト指向(OO)のような慣れない概念について説明する上で、言語の設計の動機を強調し そのメリットと潜在的デメリットを明確にするために、Fortranのような手続き型言語についても少し遡って触れることにします。

もちろん、Objective-C言語はCocoaの一つの要素にすぎません。或る者は最も小さい要素だと言いさえするでしょう。残りはフレームワーク群で成り立っています。それは、人を感動させる派手なグラフィカルインタフェースを開発して、何らかの役に立つ研究を容易にさえさせます。 そちらも始めるつもりですが、大多数のCocoa導入と異なって、私たちはコンピュータの科学者が最も付き合い易いところから出発します:それはコマンドラインです。 その後、グラフィカルなプログラムを開発するためにアップルの統合開発環境(IDE)、Xcodeに移りたいと思います。

提示される例は簡単ですが、子供の興味を引くようなものより、むしろ科学者が最も関心を示すタイプのアプリケーションを狙おうと思っています。このコースの話題は以下を含みます。構文解析/データのインポート、 テーブルとプロートによるデータの提示、ビジュアリセーション、そして、グラフィカルインタフェースで既存のレガシのあるツールを包装すること。

私は、チュートリアルをできるだけ短いものに保つことを望んでいます。時は金なり、一つの恐ろしく長い文章より多くの簡潔なチュートリアルの方が読みやすいでしょう。空き時間によって、チュートリアルは2−3週に1回現れます。 (MacResearchは基本的にボランティアに基づいて支えられています。)


Objective-Cって醜いですか? 私はそうは思いません!

今日は、醜いアヒルの子にあなたを紹介することで始めたいと思います: Objective-C。 確かにちょっと醜いかもしれませんね。Cベースのプログラミング言語であるC++、Javaのように幾つかの整備されたコンベンションに従っていないからです。しかし、Objective-C言語は実に美しい白鳥であることを保証します。数週間Objective-Cと遊んだあとには、あなたも同意せざるを得ないでしょう。皆そうなります。

実際にObjective-CはC言語のスーパーセットであり、オブジェクト指向言語とスモールトークのフランケンシュタインハーフです。メアリー・シェリーのモンスターのように、構文は初めに、少し恐ろしいことがありますが、2、3日後には 他の言語がなぜObjective-Cのようにしないかときっと思うようになります。 もっとも、これに関しては話すよりもお見せした方が早いでしょう。以下、私たちの最初のObjective-Cのプログラムです:


#import <Foundation/Foundation.h>

// -----------------------
// スタンダードインプットで入力する
// スペースで区切った数字の列の総和を計算するプログラム
// -----------------------

int main(int argc, char *argv[])
{
int retCode = 0;
NSAutoreleasePool *pool = [NSAutoreleasePool new];

// ファイルハンドルの取得し、数字をストリングへ読み込み
NSFileHandle *fileHandle = [NSFileHandle fileHandleWithStandardInput];
NSData *inputData = [fileHandle readDataToEndOfFile];
NSString *inputString =
[[NSString alloc] initWithData:inputData encoding:NSUTF8StringEncoding];

// ストリングをスペークで区切って、数字に変換
NSArray *tokens = [inputString componentsSeparatedByString:@" "];
double sum = 0.0;
unsigned int i;
for ( i = 0; i < [tokens count]; ++i ) {
sum += [[tokens objectAtIndex:i] doubleValue];
}

// 出力
NSLog(@"数字の総和はs %g.", sum);

// オブジェクトの開放
[inputString release];

[pool release];
return retCode;
}

Xcodeの複雑さを避け、Objective-Cに何ら特別なものもないことを示すためにターミナルでGCCコンパイラでコンパイルします。私たちの目的は途方に暮れないことですからね。 Capische?(カピーシュ?)

もしまだインストールしていなければXcode開発環境を整える必要があります。GCCコンパイラは中に含まれます。デベロッパーツールインストーラはMac OS Xインストールディスクにあります。もしくはアップルのデベロッパーサイトからダウンロードることができます。(ダウンロードのファイルのサイズが1GB以上であることに注意)

デベロッパーツールのインストールが済んだら好みのテキストエディターで上記のコードをAdder.mファイルに書きます。次にターミナルに行き、次のコマンドでコンパイルします。


gcc -ObjC -o adder Adder.m -framework Foundation



次に./adderで実行します。スペースで区切ったいくつかの10進数を入力します。そしてCtrl+Dでスタンダード入力のパイプを終了させます。
数字の総和が出てくる筈です。以下はセッションの例です。


./adder
1.24 2.35 245.1
2009-12-31 16:35:41.788 adder[1985:903] 数字の総和は 248.69.


Objective-Cコードのコンパイル

コンパイルコマンドから始まり、たった今起こったことを見てみましょう。通常Cocoaで開発するとき Xcodeは全部してくれますからあんなコマンドを打つ必要はありませんが、Objective-CのプログラムをコンパイルすることはC言語のプログラムと同様であることを示したかったので コマンドラインで操作を行いました。-ObjCというフラグを入れ、.cよりも.m拡張子を各ファイルに追加し そしてFoundationフレームワークにリンクする必要があります。(以前Mac OS X用にコンパイルしていなければ -frameworkリンクオプションと親しくはないかもしれません。ライブラリオプション-lと同じですが、フレームワーク用ですね。)

FoundationフレームワークはCocoaの一部です。上記のプログラムでは#importプロセッサ指示を利用してインポートされています。(#importはObjective-C言語のCの標準指示の拡張の一つです。)FoundationフレームワークはAdder.mで使用しているクラスを提供してくれます。例えばNSString、NSDataなどなどです。(NS?なぜならNSの接頭語が名前の競合を防ぐためにCocoaで全体的に用いられています。そしてNSはMac OS Xの先祖であるNeXTStepの略です)


クラスとオブジェクトの導入

クラスは、Cの構造体、またはFortran90のユーザ定義された型と同様ですが、より強力です。 私たちは、クラスの詳細な議論を後にしますが、取りあえず知らないといけないことは 各クラスが型を表現するということです。そしてクラスは変数の形でデータを含むことができます。メソッドを含むこともできます。メソッドはCとFortranの関数と手続きと同じようなものですが、違いとしてメソッドは特定なクラスに属するのです。

CとFortran 90では特定のタイプの変数を定義できます。例えばCのプログラムは以下のようなコードがありえます。


struct Cow {
float weight;
};
struct Cow c;

それをFortran 90で以下のようです

type Cow
real :: weight
end type
type (Cow) :: c

両方はインスタンス化の例です。Cow型またはタイプのcという名前を持った変数またはインスタンスを生成しています。

Objective-Cにおいてクラスを用いて同じことができます。クラスのインスタンス化をするときインスタンスまたはオブジェクトを取得します。Adder.mでインスタンス化の例は:

NSAutoreleasePool *pool = [NSAutoreleasePool new];

現時点ではNSAutoreleasePoolクラスは何をするか心配しないでオブジェクトの生成の行程に集中しましょう。この場合、変数はpoolです。(オブジェクト自体よりも 実はオブジェクトへのポインタであることに気付きましょう、Objective-Cでは常にこのようなやりかたをします。)NSAutoreleasePoolに属するメソッドnewによって poolにオブジェクトが割り当てられます。

再び、オブジェクトのインスタンス化の詳細な議論を後にしますが、取りあえずクラスは特定な型の変数とメソッドを持っています。そして、クラスをインスタンス化するとオブジェクトを取得することができます。


メッセージとメソッドの導入

このチュートリアルを仕上げるために、メッセージ送受信の仕組み(メッセージング)に焦点を合わせたいと思います。 上記のコードでメッセージングの例を丁度見たところです。メッセージングとはオブジェクトかクラスにメッセージを送ることで、FortranかCの関数や手続きを呼ぶことと似ていますが、同等ではありません。Objective-Cでメッセージを送る構文は角括弧を使用します。例えばAdder.mでは:



NSArray *tokens = [inputString componentsSeparatedByString:@" "];

このメッセージの名前はcomponentsSeparatedByString:であり、オブジェクトinputStringに送られます。(名前はコロンを含むことに注意、これは後程説明します。)@" "はObjective-Cのストリングの意味をします。特にこの場合はスペースを指します。このコードはメッセージcomponentsSeparatedByString:をinputStringに送り、スペースのストリングを引数として渡しています。

Fortran90では恐らくこの様になります:

character(len=100) :: tokens(10)
character(len=100) :: inputString
inputString = "Hello there"
tokens = ComponentsSeparatedByString(inputString, " ")

角括弧は、ある意味で、ものを逆順にします。例えば、Fortran 90の関数ではオブジェクトinputStringは第1引数として渡されています。Objective-Cでは関数(あるいはオブジェクト指向の用語を使ってメソッド)はinputStringに属するから 明示的に引数として渡す必要がありません。自動で渡されます。
引数2つ以上があると更に変になります。
例えば次のコードでは



NSString *inputString = [[NSString alloc] initWithData:inputData encoding:NSUTF8StringEncoding];

まず、ここにはメソッドが2つあります。片方はもう一つの中にネストされています。

1番目の方は簡単:alloc. 引数無し、従ってコロン無しです。Objective-Cでは引数一つに対してコロン一つがあります。
2番目の方はより複雑です。メッセージが allocメソッドの結果に送られます。2番目のメッセージの名前はinitWithData:encoding:です。Objective-Cにおいてこのような名前はセレクターといいます。メソッド名と同じようなものです。二つのコロンに対応する二つの引数があります:inputDataとNSUTF8StringEncodingです。

もっとも紛らわしいことは恐らく、メソッド名は各コロンあたり1つに分かれていくということです。これをはっきりさせるために、Cの同類の関数のコールを見てみましょう。

NSString *inputString =
InitWithData_Encoding_( AllocString(), inputData, NSUTF8StringEncoding );

Cの関数にコロンがあってはいけないため、代わりにアンダーバーを使いました。多くの言語にも言えることですがCでは関数名は連続しています。一方Objective-Cではメソッド名は連続せず、引数と混ざっていることに注意してください。

これはObjective-Cを初めて勉強するときに多分一番分かりにくいことだと思います。殆どの人々にとって慣れるには少し時間がかかるかもしれませんが、そう長くは掛からず慣れることを確信しています。
そして、一度慣れてしまえばこの仕組みの利点が見えるようになります。それらを次に説明します。
最初、実はメソッド名をセグメントに分ける(区切る)ことは任意であることを指摘するべきでしたね。Cの方法のようにメソッド名を使うことが出来ますので、以下のコードも書くことができます。


NSString *inputString =
[[NSString alloc] initWithData_encoding_:inputData :NSUTF8StringEncoding];

この方法では、(文法は大丈夫)、メソッド名を始めに全部つめました。角括弧とコロンの使用は別として、このコードはCに大変似ていますね。よってCのようなメソッド名は可能ですが、Objective-Cにとらわれないのです。そして、このメソッドは前挙げたメソッドと交換可能ではないと強調したいと思います。単に異なる命名方法が可能で、他言語と同じものが使えることはポイントですね。

このように区切られた命名というObjective-Cのアプローチは実は他の言語より柔軟です。自分のメソッド名をセグメントに分けることで引数をより説明しやすくなります。コード自体がドキュメンテーションになるので、結果的に読みやすいコードになります。そして説明用の多くのコメントを書く必要がなくなります。更に普段のように引数を調べる必要がなくなります。

例えば、CやFortranでプログラミングするときよく関数の引数やその順序を調べますが、Objective-Cでは一般にそれらは既に明白です:

[NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:error];

(英語の)文かのように読めて、しかも今度のチュートリアルで説明するようにXcodeのコード入力補助機能があるので、全ての文字を書く必要がありません。


終わりに

取りあえずここまでです。このチュートリアルのうちで、一番重要なのは、Objective-Cのメッセージ送受信の構文です。それについて次のチュートリアルまでじっくり考えてください。そして、そのアイディア・概念に慣れるようにしてください。
始めのうちは取っ付きづらいと感じるかもしれませんが、最も使われているアプローチであるからには、裏に理由がある筈です。
これを身に付ける事ができれば、残りは楽勝でしょう。

もしAdder.mにまだ分からないことがあって不安を感じているのならば、心配しないでください。詳しい解説は次回以降
行うつもりです。今日のレッスンはObjective-Cの雰囲気にあなたが慣れるように設計されただけです。それ以上のものではありません。
次回は言語をもう少し詳しく調べるつもりです、メッセージ送受信の仕組みを調べ、そしてクラスの書き方も習います。