11月2006

生成と解放

この記事には間違いがありましたので、生成と解放-2も合わせてご覧下さい。

今日は、久々にCocoaでプログラミングしています。
まだ、Cocoaでのプログラミングに慣れていないので、いろいろと苦戦しています。特に、CarbonAPIをCocoaで使おうとする時の変換などが、まだうまく把握できていません。

それはいいとして、今日は無駄にNSOpenPanelに苦戦しました。こういう無駄はプログラミングにありがちなことですね。普通オブジェクトは、初期化して、使い終わったら解放という使い方をします。

id *obj=[[Object alloc] init]; '生成、初期化
[obj release]; '解放

NSOpenPanelも何の疑いもなく、初期化、解放の流れで使っていた訳です。しかし、何度、どこで実行しても、どうしてもreleaseを使ったところで、エラーが起きてしまうのです。

'生成/beginSheetForDirectoryというのは、Windowsでいうファイル指定ダイアログ
[[NSOpenPanel openPanel] beginSheetForDirectory:NSHomeDirectory()
file:nil
modalForWindow:mainWindow
modalDelegate:self
didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:)
contextInfo:nil];

'コールバック
- (void)openPanelDidEnd:(NSOpenPanel *)panel returnCode:(int)returnCode contextInfo:(void *)contextInfo
{
'適当な処理
[panel release]; '解放
}

最初は、コールバックの位置で解放するのがいけないのかと思い、他の場所で解放したりして試してみました、結局うまくいかず。

いろいろ試しているうちに、あることに気がつきました。そもそも、このNSOpenPanelは、自分で生成、初期化をしないのです。上のコードを見ればわかると思いますが、[NSOpenPanel openPanel]は、NSOpenPanelのデフォルトのインスタンスを取得するメソッドで、生成しているわけではありません。
つまり、もともと解放する必要のないものを解放しようとしていたのです!

ということで、結構これに時間を費やしてしまいました。慣れていれば、すぐわかることなんですけどね。オブジェクトを生成するときは、最初に一番上に書いたコードのような、[[Object alloc] init]をしますからね。

論理演算

今日は、フォーラムの方で論理演算が必要になって、やっていましたが、やっぱりあの辺は苦手分野です。というか、論理演算なんてほとんどやったことありませんでした。
なぜ苦手なのかと言えば、そもそも、10進数表記のところを、2進数でかんがえなきゃならないからです。いや、その逆かもしれませんね。コード中に2進数をそのまま書く訳にもいきません。その時点でやる気失せますし、 例えば、36 And 76なんて計算結果、普通に考えて頭の中だけでは計算できません。
要するに面倒なんです。

ただ、最近あまりに抽象的なことばかりやっていたので、たまにこういうこともいいなーと思ったりします。特に、.NET Frameworkのクラス群を眺めていると、どれも抽象度が高く、たまに何のことを言ってるのか、まったく理解できないようなクラスに遭遇したりもします。
それに比べれば、論理演算なんて基本中の基本なので、簡単なのかもしれません。

マルチスレッドとデリゲート

最近よく見ているSystem.IOのFileStreamクラスを眺めていると、非同期でファイルを扱うようなメソッドが用意されていることがわかります。
そして、その非同期の仕組みを詳しく見ていると、IAsyncResultインターフェースなどが出てきます。非同期なので当然マルチスレッドなので、スレッド関連のクラスやら、非同期が終了したときに呼ばれるコールバックを、デリゲートで指定したりもします。
そして、このデリゲートが意外とマルチスレッドと絡んできているのです。まだActiveBasicはデリゲートが実装されていませんが、近々実装される予定です。

ところで、久しぶりにArrayクラスの話に戻ります。今更ですが、.NET Frameworkなどでよく書いてある変数宣言。「int value[];」こんな感じのやつは、どうやらコンパイラがArrayクラスに勝手に変換してやっているようですね。引数に何のためらいもなく、int value[]なんて指定されているメソッドがあり、どうやって配列の数をカウントしているんだろうとか、考えていましたが、結局のところArray配列なので問題ありません。
ちょっと記憶が曖昧なんですが、たしか、ActiveBasicはジェネリックというもの(私もまだよく知りませんが、型宣言をしなくてもいいみたいな感じのもの)を導入しないと聞いた気がするので、Arrayはポインタベースで操作するものになることになります。要は、以前私が作っていたArrayクラスのようなものです。
私は別に構わないのですが(Objective-Cがそうなんで)、ポインタが露出するのってのはどうなんでしょうか。まあ、その辺は置いておきまして、Arrayってのは、やはりStringと同じ水準のクラスだと認識していますので、今単独で作り始めてもそんなに問題のないクラスだと考えています。

ですので、今日は、.NET Frameworkと同じようなArrayクラスの作成を開始しました。まだ全然作っていませんが、うまく作れるといいです。

ところで、MSDNライブラリをついにダウンロードして、オフラインに導入しました。全てインストールしたので、2GBくらいでした。前のMSDNを削除して導入したので、なんとかHDDは足りたようです。

電子辞書って意外と使えるものですよ

さて、最近の電子辞書は、なにやらいろいろ機能が増えてきているようですが、私は昨日、並々な機能を持つ電子辞書を購入してしまいました。
電子辞書なんて、パソコンや携帯電話があれば必要ないじゃないか、そういう考えをお持ちの方もいるでしょう。私もその一人でしたが、実はこれは大きな間違いです。
まず、普通に辞書を使う時ですが、電子辞書は非常に速いです。いくら電子辞書の機能が増えてきたとはいえ、立ち上がりは一瞬ですし、検索方法も、インクリメンタル検索となっており、即座に表示されます。しかも、文字を入力しつつも、検索結果のリストにフォーカスが当たっており、右半分の領域で、その言葉の説明を、既に見ることができます。
辞書を便利に使うために、さまざまな機能が用意されていますが、中でも便利なのが、ジャンプ機能です。調べている語の説明で、分からない語があった場合、そこを選択してジャンプすると、その語を任意の辞書で、さらに引くことができるのです。

このように、レスポンスがこれ以上ないくらい電子辞書は、携帯性も考えて、かなり使えるのです。

そして、特にCASIOのですが、電子辞書付属の機能として最もうれしいのは、.txtファイルを、電子辞書に取り込めることです。
本体メモリは20MB以内、SDも使えるので、容量は申し分ないです。これで任意のテキストファイルを携帯することができます。この場合も電子辞書は素早いですし、レジューム機能がついているので、電源を切って入れ直しても、その場所からまた読み始められます。もし、テキストファイルを読んでいる途中に辞書が使いたいのならば、しおり機能が付いているので、どんな長い文書を読んでいても安心です。
また、テキストファイルにおいてもジャンプ機能は有効ですので、わからない語があったらすぐに調べることも出来ます。

肝心の文章は、自分で適当なWEBページから取ってきてもいいですし、青空文庫から小説1冊まるまる入れることもできます。
どうでしょうか?電子辞書は意外と使えるのです。これくらいの機能を持つ電子辞書は、だいたい3万円くらいが多いですが、私はたまたま2万で購入することができました。

ちなみに、テキストファイルが自由に入れられる電子辞書は、CASIOのXD-STの型番のやつが多いです。他の電子辞書では、テキストファイルを入れる機能は、あまり見かけませんでした。

オフラインヘルプ検討中…

MSDNのレスポンスも、相変わらずで、最近エラーを返すこともしばしばあって、メソッドを書き写したりするのには、どうしても無駄な時間を消費してしまいます。

まだ、ActiveBasicの様子を見るという選択も、ないわけではないので、MSDNのレスポンスがそのうち改善されることを期待しつつ、とりあえず次のバージョンアップまでは様子を見ることにします。

もし改善されないようであれば、MSDNのダウンロードってことになるでしょうか。HDDあまりないので、やりたくないのですが、仕方ないですね。

ちなみに、様子を見ている間は、一応ライブラリ開発に関係するようなことをやろうと思います。

えーと、ちなみに。この前実装していたDateTimeですが、実装中にも薄々気づいてはいたのですが、あれは.NET Frameworkと結構違うんですよ。
具体的に言えば、Ticksまで必要ないと思い、それぞれのメンバ変数作って時間を保存していたのです。しかし、.NET Frameworkの方は、どうやらTicksの単位で全ての時間を保存しているようです。これは64bit変数型でぎりぎり日付や時間を保存できる単位です。具体的に言えば、100ナノ秒単位で、年号から表しますので、凄い大きな値になります。

今のところPCで時間が取得できる単位は、ミリ秒単位だったので、いらないかなーと思って削ってやってましたが、やっぱり変えた方が良さそうです。

MSDN探検中…

ActiveBasicのライブラリは、とりあえず.NET Frameworkを真似て作るような感じで進んでいるようです。まだまだどうなるか、わかりませんけどね。
本当はWindows.Formsの方を手に着けるつもりだったのです、大規模だったので、System.IOをやろうかと思ったのは、以前話した通りです。

そのSystem.IOですが、やっぱり目玉はStream関連のクラスでしょう。非同期的にファイルの読み込みがサポートされれば、どんなにうれしいことやら。
しかし、Streamクラス実装するには、なにやらいろいろと絡んでくるので、特に、スレッド関連の方は、まだ安定しなさそうですし、まだちょっと手をつける気にはなれない感じです。

そんなわけで、Streamの方は置いといて、回りのFileクラスやDirectoryクラスに手をつけているのです。そして、ここで頻発してくる構造体が、DateTime構造体。あまりに頻発して出てくるので、こちらから実装に移っていました。そこそこ出来上がってきているので、あとはDateTimeと似たようなTimeSpanを実装し、そしたら、またIO関連に復帰できそうです。

こうしていると、.NET Frameworkはある程度予測はしていましたが、さまざまなクラスが連携して出来ています。ですから、たとえ個々のクラスが実装できると言っても、全体を把握していなければ、うまく作ることができません。
そんなわけで、今日はMSDNの探検に時間を費やしてしまいました。おかげで、System.IO辺りは、だいたい把握できました。TextReaderクラスあたりは、実はStreamとは関係なかったりと、Streamを作らなくても、それなりには実装できそうですね。

ところで、かなりマイペースな開発スピードですけど大丈夫でしょうかね。このペースだと年内にSystem.IO辺りを完成させるのでさえ怪しいです。

ついでに、最近MSDN2がSafariで閲覧できなくなってしまったのは、非常に残念です。(といっても、左側の階層が表示されないだけです。)
要するに、、、「寒いのがまんしなさい!」ということでしょうか?

冬とプログラミング

実は、この時期になるとある問題が発生します。
そう、寒いのです。どうしても昼間には自由にパソコンを使っていられませんから、プログラミングも夜するわけです。ここ最近いっそう寒さが増し、パソコンの前に座るのでさえ面倒になってきてしまいます。暖房器具を使えばいいじゃないかって思うかもしれませんが、うちの暖房器具の主力はこたつです。それ以外はエアコンなどもあるにはあるのですが、よっぽど寒いときにしか使いません。
そして、そのこたつ。デスクトップのパソコンを使う時は、当然こたつの上にはないわけですから、こたつから出なくてはならないのです。ですから、毎年毎年冬は寒い思いをしながらパソコンを使っていたわけです。

ところが今年は違います。今年の6月くらいに買ったノートパソコンがあるのです。これならこたつに入りながらパソコンを使うという、夢のような環境が整っているわけです。
そんなわけで、こたつに入りながらパソコンを使っているわけですが、ひとつ問題が….

このパソコン、iBookですからActiveBasicでプログラミングできないんですよね。当然ライブラリ開発もできません。
さーどうなるでしょうか、最近デスクトップを使う頻度が、ただでさえ減少していた(というより、最近はAB以外に使ってなかったかも)ので、どうにかしたいものですね。

要するに、「寒いのがまんしなさい!」ということですね。

DateTime.Add()

本日は、DateTime.Add()のTimeSpanを引数に取るもの以外を実装しました。
Add()の引数が小数も取れるということで、実装が面倒そうだとばかり思っていましたが、実際作り始めると、意外に簡単なもの。
例えば、AddDays(1.5)で加算する時は、内部の計算を3つに分けます。
1.整数部分を加算
2.単位切り上げ
3.小数部分を加算
具体的には、1で単純に日に加算し、2で1ヶ月の日数よりも多くなっている場合、AddMonths()、3で小数部分をAddHours(0.5 * 24)
こんな感じの処理を、各単位ごとにやっていけば実装完了です。やはりAddDays()は一番面倒で、月ごとに日数が変わったりするのが特に面倒でした。
あと、曜日を求めるツェラーの公式というのは初めて知りましたね。早速それでDayOfWeekは実装しました。

まだ未完成でデバッグも不十分ですが、興味のある方がいるかもしれませんので、DateTimeの試作品をUPしておきます。
datetime.ab.zip
ファイル名を変更しただけで、圧縮は施していませんので、そのままファイル名の.zipの部分だけ削除してファイルを開いてください。特定の拡張子しかアップできないようなので、拡張子をzipにしておきました。

さすがMSDN2ライブラリ

もう既に10分以上経過していますが、目的のページへ到達できません。
こんなレスポンス悪いヘルプ使いたくないですよ。ホントに。昨日より酷い状況に陥っている…

これだけでも開発のモチベーション下がります。そんなもんなんですよね。こんな.NETみたいにならないように気を付けなければなりませんね。

DateTime

一昨日の作業に引き続き、ファイル関連のクラスによく使われる、時刻を表すDateTime構造体?を作成しています。msdn libraryには、DateTime構造体と書かれていますが、クラスにしかみえないので、とりあえずDateTimeクラスとして実装しています。DateTime構造体 (msdn2)
順調にプロパティはほぼ実装完了したのですが、メソッドに取りかかろうと、Addを見てみると、TimeSpanクラスが必要になるようなので、これはひとまず置いておき、簡単そうなAddDaysを実装することに。

Function AddDays(value As Double) As DateTime

さて、このコード。何か思いませんか?
これは、指定した日数を加算するメソッドですが、日数にも関わらず、引数がdouble型なのです。要するに、小数が指定できる訳です。例えば、0.5日加算するといえば、1日の半分の12時間加算するようにするわけです。
これで、一気に面倒なことになった気がします。

それで疑問に思うのが、小数を指定して時計を進める人はどれだけいるかということ。普通に考えて、正確に時間を加算したい場合は、使用しないでしょう。端数が出るような値を加算していったとすれば、時間がずれていきますからね。ですから、それほど、細かい時間を気にしないようなところで使われるのでしょうね。

AddDays()の端数分をAddHours()、そしてAddHours()の端数分をAddMinute()、その端数分を….ってやっていけば、少しは簡単に実装できるのかなぁーと考えつつ、今日の作業はこの辺で終了です。
それと、今はAddDays()とかは、戻り値にその結果を返すように作っていますが、Stringクラスの時のように、自分自身のインスタンスの値を変えてしまうのもいいかもしれませんね。変えるのか変えないのか、クラスによって変わるのもあれなので、どちらかに統一したほうが良さそうですね。

MSDN2の表示速度が遅くてやる気が失せますね。特に今はなぜか、メニューがずっとloading…のままに..