2009年5月7日木曜日

Objective-CではvalueForKeyPath:で集計関数みたいなものが使えて凄く便利

Pythonだと、
list = [{'no':1, 'name':'akisute'}, {'no':2, 'name':'abesi'}, {'no':3, 'name':'hidebu'}]
maxNo = max(list, key=lambda x:x['no'])
こんな感じでリストに含まれるオブジェクトの最大値を簡単に取り出せたりするのですが、Objective-Cでもできないかと思い調べてみました。ですが、NSArray自体にはそのようなメソッドが用意されていません。ひょっとして出来ないのかと思っていたら、ちょっと面白い方法で集計関数のようなものが実装されていることがわかりました。

Objective-CにはKey-Value Codingという概念があって、それを使って実装されているようです。Key-Value Codingについては正直全然理解していないのでここでの解説は避けます。すみません。

NSArrayのvalueForKeyPathを使って以下のように問い合わせを行うと、先ほどのPythonの例と同様にNSArray中の最大値を持つオブジェクトを取得することが出来るようです。
// noとnameプロパティを持つPersonクラスがあると仮定して・・・
id akisute = [[Person alloc] initWithNo:1 name:@"akisute"];
id abesi= [[Person alloc] initWithNo:2 name:@"abesi"];
id hidebu= [[Person alloc] initWithNo:3 name:@"hidebu"];
NSArray *array = [NSArray arrayWithObjects:akisute, abesi, hidebu, nil];
NSNumber *maxNo = [array valueForKeyPath:@"@max.no"];
valueForKeyPathの引数に、@max.noというキーを渡すところがキモです。これで、NSArrayのインスタンスに含まれるオブジェクトのnoプロパティの最大値を求めることが出来ます。
同様にして、名前の最大値を求めたいときには、
NSString *maxName = [array valueForKeyPath:@"@max.name"];

とすれば取れます。また、一番長い名前の長さを求めたいときは、以下のように指定することができます。
NSNumber *maxCountOfName = [array valueForKeyPath:@"@max.name.count"];

@max以外にも、@avg, @sum, @count, @min, @unionOfObjects, @distinctUnionOfObjectsなどが用意されているみたいです。

詳しくは荻原さんのObjective-C 2.0本をご参照あれ。いや、この本は本当に買ってよかったです。Objective-Cのバイブルですね。

詳解 Objective-C 2.0
荻原 剛志
4797346809

Windows起動時にhal.dllが見つかりませんと言われた場合の対処法

久しぶりにBootCampでWindows XPを起動しようとしたら、hal.dllが見つかりませんといった具合のエラーメッセージが表示されてうんともすんとも言わなくなってしまいました。dllが破損したのかと思い調べてみたところ、このエラーメッセージはC:¥boot.iniファイルの設定が破損された場合に表示されるメッセージだと言うことが分かりました(さすがマイクロソフト、エラーメッセージの意味不明さには定評があります)。なるほど、確かにboot.iniファイルが消えてました。

修復するにはWindows XPをCDから起動して、回復コンソールを立ち上げます。画面の表示に従えば大丈夫だと思います。
回復コンソールが起動したら、以下のコマンドを入力。
bootcfg /list

これで起動設定(boot.iniファイルの中身)の一覧が表示されます。私の場合は、boot.ini自体が存在しないので、設定がありませんと怒られてしまいました。
設定が破損しているのを確認したら、以下のコマンドで修復を行います。
bootcfg /rebuild

途中、3回ぐらい選択肢が表示されますが、以下のように回答します。
インストールをブート一覧に追加しますか?
YES

ブートIDを入力してください
適当でかまいません。MacでBootCampしている私の場合はWindowsと入力しました。普通のWindowsマシンの場合にはWindows XP Professionalとか入れておくとわかりやすいのではないでしょうか。

オプションを指定してください
/fastdetect

これで完了です。あっさり終了するのでちょっと拍子抜け。あとはコンピューターを再起動すれば問題なくWindows XPが起動すると思います。

2009年5月4日月曜日

Objective-CのnilとNULLの違いって何?

自分用メモ。
nilは「Objective-Cの空のオブジェクト」、NULLは「C言語の空ポインタ」と解釈する。もっとも良い例がNSFileManagerのcreateDirectoryAtPath:withIntermediateDirectories:attributes:error:です。
http://developer.apple.com/DOCUMENTATION/Cocoa/Reference/Foundation/Classes/NSFileManager_Class/Reference/Reference.html#//apple_ref/occ/instm/NSFileManager/createDirectoryAtPath:withIntermediateDirectories:attributes:error:

リファレンスを読んでみると、attributes:の指定が不要なときはnilを、error:の指定が不要なときはNULLを引数として与えろと明示的に書かれています。これは、attributes:が(NSDictionary *)型=NSDictionaryのオブジェクトを引数として受け取るのに対して、error:は(NSError **)型=NSErrorのオブジェクトのポインタを引数として受け取るためだと考えられます。といっても私はObjective-CもC言語もド素人ですので、ひょっとしたら大嘘かもしれません。違ってたらごめんなさい><


※追記:やっぱり定義そのものが違った><
すたっくおばふろ曰く(http://stackoverflow.com/questions/557582/null-vs-nil-in-objective-c
えらいひと曰く(http://www.libjingu.jp/trans/clocFAQ-j.html#objects-nil


知らないとついつい全部nilもNULLも同じだろと思いnilって指定してしまいそうですね。おそらくnilを指定しても動くとは思いますが・・・Objective-CとC言語の混ざり合いというか関わり合いがこんなところで垣間見れて面白いです。