11月2009

Objective-C Blocks を使ってみる 1

iMacを買って、せっかく新しい開発環境も揃ったので、早速気になるブロック構文を試してみます。一般に、クロージャとか呼ばれているものに似ているらしいですが、そもそもクロージャ自体あまり知らないので、恐る恐る試している次第です。とりあえず手始めに、Wikipediaに書いてあるクロージャコードを、Objective-Cで書いてみることにしました。

クロージャ(Wikipedia)のJavascriptの例

function newCounter() {
     var i = 0;
     return function() { // 無名関数
         i = i + 1;
         return i;
     }
 }

 c1 = newCounter();
 alert(c1()); // 1
 alert(c1()); // 2
 alert(c1()); // 3
 alert(c1()); // 4
 alert(c1()); // 5

Objective-Cで書くと、こうなるはずです。

#import <Foundation/Foundation.h>

typedef int (^Counter)(void);

Counter newCounter()
{
	__block int i = 0;
	return [[^(void) {
		i += 1;
		return i;
	} copy] autorelease];
}

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

	Counter c1 = newCounter();
	NSLog( @"%d", c1() ); //1
	NSLog( @"%d", c1() ); //2
	NSLog( @"%d", c1() ); //3
	NSLog( @"%d", c1() ); //4
	NSLog( @"%d", c1() ); //5

    [pool drain];
    return 0;
}

あまり綺麗でないですね。綺麗にならない理由をちょっと解説。

もっとも大きな理由は、ブロックはローカルスコープを抜け出すと、ブロックが消失してしまう点です。なので、コピーメソッドを呼び出して、コピーしておきます。コピーするということは、どこかで破棄しなければならないので、autoreleaseメソッドも投げるわけです。ちなみに、見ての通りブロックにはメッセージ式でメッセージを投げることができるようです。Cでやる場合には、Block_copy()やBlock_release()関数を使用します。

もうひとつ、変数iの宣言に修飾子が付いています。これは、ブロックの中で変数iの値を変更できるようにするためのものです。デフォルトでは、ブロックの外側の変数は、読み出しのみ可能で、書き込みはできないようです。なので、__block修飾子を付けて変数を宣言します。

最後に、newCounterの戻り値の型です。どうしても、戻り値の型に直接ブロックの型を記述する事ができなかったので、上でtypedefして一旦型定義をし、その後で関数定義しています。どういう書き方をすれば直接書けるのか、よくわかりません。

とりあえず、なんとなくブロックというものがわかりました。しかし、まだ使い道が思いつかないので、ドキュメントを見ながらいろいろ試してみることにします。

iMac買いました

先週の水曜日にiMacが届いて大興奮。ようやく落ち着いてきたので、iMacを購入してから、環境をセットアップする過程でもブログに書いておきます。今回は、LeopardのiBookから、Snow LeopardのiMacに移行する過程となります。

ちなみに、購入したiMacは21.5inchの上位モデルです。下位モデルを選ばなかったのは、店頭でExposéをしてみると、アニメーションがあまり滑らかでなかったからです。21.5inchの上位モデルならば、27inchの下位モデルを買ってもよかったかもしれませんが、別の理由により、27inchは選びませんでした。それでは、iMacを箱から出して、iMacに電源コードを繋ぎ、キーボードとマウスと共に机に置いたところから話をはじめます。

電源を入れると、例によっていつものセットアップが始まります。今回は、出荷時にインストールされている状態で使用するので、最初から再インストールなんてことはしませんでした。

まず、マルチIMクライアントであるadiumをインストールしました。そして、スキンを設定し、前のiBookからチャット履歴をコピーしました。チャット履歴は、Application Supportsのそれっぽいファイルをコピーすれば、問題なくadiumは認識してくれるようです。

adiumと一緒に、growlも付属していたので、とりあえずgrowlもインストールします。

次に、音楽を流したかったので、iTunesを移行しました。やり方が正しいかとても怪しいのですが、iBookのiTunesフォルダをiMacのフォルダに上書きしました。とくに今のところ問題はないのですが、正しい方法かわかりません。

次に、おもにiPhoneの中に入ってるようなデータ、すなわち、ブックマークやアドレスブック、スケジュール、メールアカウントなどを移行しようと思いました。最初は手動でやろうと思ったのですが、iPhoneからiMacに同期できないのかと考え、iPhoneをiMacに繋ぎました。

最初は無理だと思ったのですが、意外なことに、アドレスブック、スケジュール、ブックマークは、iPhoneからiMacへ逆に同期させることができました。これができたのは、iTunesフォルダを事前に移行させていたせいかもしれません。ただし、両者は異なるMacなので、購入したアプリケーションや音楽については、認証を解除しなければ使用できないようです。認証を解除すると、5回までの制限が1回分なくなります。

ただし、メールアカウントの同期はできなかったので、手動でアカウントのセットアップをし直しました。

テキストエディタが欲しかったので、CotEditorをインストール。
RSSリーダーが欲しかったので、NetNewsWireをインストール。これはもともとGoogleReaderを利用しているので、アカウントを設定するだけでいいです。

最後に、Xcodeをインストールし、とりあえずいつもの環境になった気がします。

ちなみに、Social IM も入れたところ、Snow Leopardでも問題なく動作してくれています。

使い勝手については、また後日ブログに書くことにします。
Windows環境も欲しいので、Windows7も入れたいのですが、Windows7高すぎます。残念。

Flash上の動画がカクカクする噂

新しいiMacのFlash上で、比較的重い動画を再生しようとすると、Mac全体が重くなって、そのまま戻らなくなるといったような噂が立っています。AirMacでネットワークに接続している場合起きるようなので、そのへんのバグなのだろうと予測されています。

しかし、Mac OS X上のFlashの実装は、決してよいものとは言えないでしょう。なぜなら、新しいiMacに限らず、少なくともこのiBookでも、Flash上の動画再生は重いからです。Flash上で動画を再生する場合、通常の動画再生アプリケーションで再生するよりも、なぜか格段に重くなるのです。QuickTimeなどで余裕で再生できる動画でも、Flash上ではカクカク再生になってしまうことは多々あります。Adobeさんにはもうちょっと頑張ってもらいたいところです。

そんなわけで、なかなか新iMacの購入に踏みきれないのであります。