Pages

ラベル Cocoa の投稿を表示しています。 すべての投稿を表示
ラベル Cocoa の投稿を表示しています。 すべての投稿を表示

2011-07-24

ビュー・ベースのNSTableViewをさわってみたよ(その2) カスタムNSTableRowViewの設定方法

ビューベースのテーブルビューは、NSTableView → NSTableRowView → NSTableCellViewという階層構造になっています。

ところが、Xcode 4.1上のInterface BuilderでビューベースのテーブルビューはNSTableView → NSTableColumn → NSTableCellViewとなっていて、NSTableRowViewについてはInterface Builder上で直接さわれないようになっています。

NSTableRowViewのサブクラス(ここではMyTableRowViewとします)をInterface Builder上で設定するには、まずNSTableColumnの子(つまりNSTableCellViewと同じ階層)にカスタムビューを追加します。

つぎに、追加したビューを選択し、インスペクタでクラス名をMyTableRowViewにします。

最後に、User Interface Item IdentifierをNSTableViewRowViewKeyと設定すれば、カスタムクラスの設定は完了です。

わかってしまえば簡単ですが、なんともわかりにくいような……。

2011-07-23

ビュー・ベースのNSTableViewをさわってみたよ

Lionでましたね。世のCocoa系男子の皆さんはAPI Diffを見て興奮したり、新APIのGuideを眺めたり、各所をclass-dumpして廻ったりしていると思います。

さて、Lionではついに念願のビュー・ベース・テーブルビューがサポートされました。要するに、今までテーブルの中身はセルじゃないといけなかったのが、ビューを突っ込めるようになったということです。これで「プログレスバーがテーブルビューに入らない!」なんて騒ぐ必要がなくなりますね。NSCollectionView使えば同じようなことできるけど、そんなの知りません。

というわけで、ビューベースのテーブルを作ってみましょう。

Xcode 4.1内のInterface Builderでxibを開き、適当なウインドウにテーブルビューを追加します。そして、インスペクタの中にContent Modeっていう項目があるので、View Basedを選択します。

すると、NSTableColumnの直下にNSTableCellViewなんていうセルだかビューだかどっちなんだよって感じの名前のビューが追加されます。このビューがセルの代わりにテーブルコンテンツの表示を担います。

このNSTableCellViewをInterface Builderで適当にデザインしてあげましょう。ここでは画像とテキストを一つずつ表示するビューにしました。

次に、テーブルビューのコンテンツを保持するNSArrayControllerを追加し、これに対してバインディングを設定します。

まず、NSTableViewのcontentをNSArrayControllerのarrangedObjectsにバインドします。注意したいのは、従来のセルベースのテーブルではNSTableViewではなくNSTableColumnをNSArrayControllerにバインドしてたんだけど、ビューベースではNSTableViewにバインドしなければならないという点です。忘れがち。

次に、ビュー上のアイテムをバインドする必要があるわけですが、バインド先はNSTableCellViewにします。

あとは、NSArrayControllerに適当なコンテンツを設定するよよう実装してビルドして実装すれば、ビューベーステーブルの出来上がり。


ここで使ったプロジェクトをGitHubにおいておきます:ViewBasedTableSample

2011-07-06

libxml2を使って強引にWebアーカイブを作成する

前回のエントリで、WebArchive *archive = [[[webView mainFrame] dataSource] webArchive];とすることでWebアーカイブを得ることができると書きましたが、これはOSXにおけるWebViewの話で、iOSのUIWebViewではそもそもWebFrameやWebDataSourceにアクセスできないのでこの方法ではWebアーカイブを取得できず、別の方法でやってやる必要があります。

というわけで、libxml2です。Webアーカイブはplistで、その構造もわかっているので、必要なのはWebページの周辺リソースを洗い出すことなわけですが、これをlibxml2でやってやります。libxml2はOSX/iOSの両方で利用でき、非整形なHTMLでもある程度パースできるので、XPathで外部リソースの在り処を探し出してplistにくるんでやれば一応Webアーカイブができ上がります。ちなみに今回は下の3つのXPath式で探すことにしました。

//img[@src]
//script[@src]
//link[@rel='stylesheet'][@href]

これで外部の画像、スクリプト、スタイルシートを探し出し、前回のエントリで紹介したフォーマットでアーカイブすれば完成です。

一応動くものをGitHubに置いておきました。 stake/STWebArchiver - GitHub

ただしこの方法には欠点があって、HTML本体から直接参照されているリソースしか取得できません。たとえば、img要素で埋め込まれている画像は取得できますが、CSSで指定されている画像は取得できません。要するに中途半端です。じゃあ使いどころがないかといえば、そんなこともないです。CSSで画像を使った派手な装飾がされていなくて、テキスト中心で、たまに本文中に画像が埋め込まれてるようなページ(InstapaperとかInstapaperとかInstapaperとか)をアーカイブする時なんかには普通に有用な気がします。

2011-07-05

SafariというかWebKitのWebArchiveについて

Safariで閲覧中のページを保存しようとしたとき、保存形式に「Webアーカイブ」ってのが選べますよね。そのページで利用されているリソース一式が1つのファイルを保存できる便利なアレです。

CocoaでWebアーカイブを扱う方法

そのWebアーカイブをCocoaで扱うには、WebKitのWerArchiveというドンピシャな名前のクラスを使います。次のようにすることでWebViewで表示中のページのWebアーカイブを取り出すことができます。

WebArchive *archive = [[[webView mainFrame] dataSource] webArchive];

ここで得られたWebArchiveオブジェクトは- dataというインスタンスメソッドを持っていて、そこで返されるNSDataオブジェクトをファイルに書き込むことでWebアーカイブファイルを作成することができます(拡張子を.webarchiveにすればSafariでちゃんと開けます!)。

また、WebアーカイブファイルをNSDataとして読み込めば、そこからWebArchiveオブジェクトを生成してWebViewに読み込ませることができます。

WebArchive *archive = [[[WebArchive alloc] initWithData:webArchiveFileData] autorelease];
[[webView mainFrame] loadArchive:archive];

Webアーカイブの中身

Webアーカイブの中身はバイナリplistです。試しに.webarchiveファイルをProperty List Editorにドロップしてみればちゃんと中身を見ることができます。plistということは、中の構造さえわかってしまえばWebKitを使わなくてもCocoaからあんなことやこんなことができちゃうわけです。というわけでplistの内容をチェックしていきましょう。WebアーカイブplistのルートはDictionaryになっています。

WebMainResource
Dictionary。周辺リソースではなくそのページ本体について、以下のキーをもちます。
WebResourceData
Data。本体のデータです。HTMLページの場合はそのHTMLをNSData形式にしたものが入ります。
WebResourceFrameName
String。ここでは空欄。WebSubframeArchives絡み(後述)で使います
WebResourceMIMEType
String。そのまま。text/htmlとか。
WebResourceTextEncodingName
String。UTF-8とか。
WebResourceURL
String。その本体リソースが本来あったURL。
WebSubframeArchives
Array。後述。
WebSubresources
Array。ページに埋め込まれている画像やスクリプト等の外部リソースについて、(WebMainResourceと同じように)WebResourceData、WebResourceMIMEType、WebResourceURLのキーを使ってDIctionaryを作り、Arrayに追加していきます。SafariやWebKitが作ったWebアーカイブにはこれらの他にもリソース取得時のNSHTTPURLResponseインスタンスがWebResourceResponseというキーでアーカイブされているのですが、これを消しても正常に表示できるようなので、要調査。

WebSubframeArchivesは、frame、iframe、objectといった要素で埋め込まれた外部ページのWebアーカイブをそのまま追加します。つまり、a.htmlの中のフレームにb.htmlが読み込まれている場合、a.htmlのWebアーカイブしようとする場合には先にb.htmlのWebアーカイブを作成し、その結果をこのWebSubframeArchivesのArrayの要素として追加する必要があります。このときのb.htmlのアーカイブは、さっきは空欄にしたWebResourceFrameNameにa.htmlでのフレーム名が入ります。

おわりに

上で見たように、WebアーカイブはただのplistなのでCocoaから簡単にいじることができるので、単なるファイル保存用途にとどまらず、いろいろな活用法があるかもしれません。CocoaじゃなくてもWindowsならCFLiteを使えば多分plistを扱えるとおもうので、ここはおひとつ試してみてはいかがでしょうか。

2009-08-31

Snow Leopardで利用可能になったAssociated Object

Leopardで大幅に手を加えられたObjective-Cのランタイムですが、Snow Leopardでもちょこっとだけランタイムに手が加えられました。それがAssociated Objectです。こいつはあるオブジェクトに対してキー付きで任意のオブジェクトをひも付けすることができるもので、ランタイム関数を使うことで簡単に扱えます。コードはこんな感じ。

id obj = ...;   // 任意のオブジェクト
NSString *key = @"key";    // キー

objc_setAssociatedObject(obj, key, @"value", OBJC_ASSOCIATION_RETAIN);

objc_getAssociatedObject(obj, key);   // → @"value" が取り出せる

objc_setAssociatedObject()で、オブジェクトに他のオブジェクトをひも付ける。2つ目の引数に取り出すときのキーを設定するんだけど、これはvoid *なので別にNSStringじゃなきゃいけないとかいうわけではありません。4つ目の引数はオブジェクトの扱い方。ここではOBJC_ASSOCIATION_RETAINを渡しているので、ひも付けたオブジェクトはretainされる(はず)。

取り出すときはobjc_getAssociatedObject()を使う。元のオブジェクトとキーを渡すことでひも付けたオブジェクトを得られます。ちなみにobjc_removeAssociatedObjects()なんてのもあって、オブジェクトのひも付けを解除できます。

で、どういう時にこのAssociate Objectが役立つかというと、カテゴリで既存のクラスを拡張する時。カテゴリではメソッドを追加できるけどインスタンス変数は追加できない、でも値を保持したいってときにこのAssociated Objectが役に立つはず。多分。今のところAppleのドキュメントにはどこにもこれに関する記述はありませんが、Square Signals : Your New Friends: Obj-C Associated Objectsのように参考になるエントリがいくつかあります。

Snow Leopardで利用可能になったブロック構文

Snow Leopardでは、C/C++/Objective-Cでブロック構文が使えるようになりました。今のところGrand Central Dispatchとともに語られることが多いようですが、GCD専用とかいうわけでは全然なくて、汎用的な無名関数とかラムダみたいな感じで簡単に使えます。こんな感じ。

void (^block)(id);

block = ^(id obj) {
    NSLog(@"%@", obj);
};

block(self);

これと同時にCocoaも拡張されていて、NSStringの- enumerateLinesUsingBlock:といったように、ブロックを引数として取るようなメソッドがいくつか追加されています。メソッドだけでなく新しいクラスも登場していて、NSBlockOperationのようにブロックを用いてNSInvocationOperationと同じようなことができるクラスも追加されています。

2009-08-29

Snow LeopardのNSTextViewでテキストの自動置換を有効にする方法

各所で話題になってるSnow Leopardですが、その中でちょっと嬉しいけど地味な新機能としてテキストの自動置換機能があります。正式名称はなんていうのか知りませんが、システム環境設定→言語とテキスト→テキストで設定できるアレです。テキストエディットとかでは使えるんですが、サードパーティのアプリはそれぞれが対応する必要があります。

対応と言っても大掛かりな実装は必要なく、テキストの自動置換機能を有効にしたいNSTextViewに対して- setAutomaticTextReplacementEnabled:YESを送ってやるだけです。これはSnow Leopardで新たに登場したもので、その名の通り自動置換を行うかどうかをセットするためのものです。ちなみにInterface Builderから"Text Replacement"にチェックをいれても変更できます。おお、簡単。

Snow Leopardでは他にもテキスト周りの新機能(スペルの自動修正とか)があり、それに関するメソッドがNSTextViewに追加されています。追加されたメソッドの一覧がADCで見られます。

2009-05-27

書籍版「Dynamic Objective-C」

つい最近までマイコミジャーナルで連載されていたダイナミックObjective-Cの書籍版、Dynamic Objective-C の(HMDT本恒例?の)プレゼントキャンペーンが始まったみたいです。当選率が上がるようなのでちょこっと紹介させていただきます。

Webでの連載はCocoa初心者向けの入門記事みたいなのではなくて、Objective-Cを使ってる人がそのディープな領域にのめり込んでしまうような、そんな魅力を伝えてくれるもの。Objective-Cのランタイムの話だとか、実装はどうなってるかみたいな深い(そしてマニアックな)話題を提供してくれて、かなり読み応えがありました。中盤以降はGoFのデザインパターンをObjective-Cではどのようにして実装できるかかも解説されてます。

書籍版はWeb版と内容はほとんど同じらしいけど、やっぱり読みやすさは紙媒体が一番だと思うから欲しい。というわけで当たるといいなー…

2009-02-18

Spotlightで特定の属性を持つファイルを検索する

例えば、OMタグを持つファイルやフォルダを集めたいときは“kOMUserTags属性を持つ”みたいな感じの式を書けばいいんだけど、これがなかなか書けなかった。

結局、kOMUserTags == '*'って書いてMDQueryやNSMetadataQueryに渡せばいいみたい。最初はkOMUserTags != ''って書いて上手く行かなかったんだけど、考えてみれば当然ですね。

2009-02-06

QSBプラグインの作り方

Google Quick Search Boxプラグインの作り方。意外とまとまった情報があまりなかったので個人的メモを兼ねて。QSBのプロジェクトページからQSB本体のソースコードが手に入る。

まず、プラグイン(拡張子.hgsのCocoaバンドル)の中心となるのはHGSExtensionのサブクラス。ただしHGSExtensionをそのままサブクラス化するのではなく、すでに種類別にいくつか用意されているHGSExtensionのサブクラスをさらにサブクラス化して実装する。例えば、QSBでは選択したアイテムに対してアクションを実行することができるけど、このアクションを追加したいときはHGSActionっていうHGSExtensionのサブクラスをさらに拡張すればいい(QSBOpenMetaもローカルファイルに対するアクションだから、HGSExtension > HGSAction > QSBOpenMetaのようになっている)。サブクラスで実装しなければならない諸々のメソッド等はソースコードにコメントがあるし、デフォルトで組み込まれてるプラグインのコードがわかりやすいから参考になる。ちなみにアクション(HGSActionを継承)の場合、最低限-performActionWithInfo:と-doesActionApplyTo:の2つを実装すれば大丈夫。前者は実際にアクションを実行するメソッドで、後者はユーザの選択したアイテムがアクションの処理できるものかどうかを判定するもの。

サブクラスを実装したら、Info.plistを編集。HGSExtensionsってキーのArrayを追加して、そこに実装したHGSExtensionサブクラスの数だけDictionaryを追加していく。下はアクションを実装したときにDIctionaryで設定する内容。

HGSActionDirectObjectTypes
アクションが対象とするオブジェクトの種類。QSBOpenMetaの場合はローカルファイル限定だから、fileとした。
HGSExtensionClass
アクションを実装したHGSActionのサブクラス名
HGSExtensionIdentifier
そのアクションの識別子。バンドルの識別子ではない。プラグイン内で複数のHGSExtensionを実装した場合はそれぞれに違う識別子を与える。
HGSExtensionPoint
拡張の種類。アクションの場合はHGSExtensionPoint。
HGSExtensionUserVisibleName
実際に表示される名前。"Add OpenMeta Tag"みたいなの。

ざっとこんな感じで、別段難しいような所はないはず。ドキュメントが用意されてないので、もしかしたら間違ってるところがあるかもしれない。Developer Previewを名乗るならドキュメントぐらい用意してくれてもいいのに…。

2009-01-30

Cocoa用OpenMetaクラスの疑問

先日CocoaアプリケーションからOpenMetaによるメタデータを操作するで書いたように、CocoaアプリケーションからOpenMetaによるメタデータを操作するにはGoogle Code上で公開されているOpenMetaクラスを利用するのが簡単です。しかしこれ、使っていくうちに色々と首を傾げたくなる部分が出てきます。

1. メソッド名がCocoaの命名規則に則っていない

まず最初に気になるのがこれ。例えばファイルに付けられたタグを得るには+ [OpenMeta getUserTags:url:]というクラスメソッドを使いますが、これはメソッドの返り値としてタグを配列を得ることができます。普通Cocoaでは求めているオブジェクトが返り値から得られるとき、メソッド名にgetは付けません。getを付けたときは普通引数に目的のものをコピーすることを意味します。もちろん、DOM APIのように外部で標準のAPIが定められている場合はこれに当てはまらないこともありますが、Cocoa内で完結するものはたいていこの規則に従います。しかしOpenMetaはなぜかこれを無視しています…

2. メソッド名が意味不明

OpenMetaアプリケーションはたいてい最近使ったタグを簡単に扱えるようになっています(OMWizardやQSBOpenMetaも自動補完という形で対応しています。OMWizardのほうは少し不具合がありますが…)。このリストは全OpenMetaアプリケーションで共有されていて、アプリケーションからこれを更新するには+ [OpenMeta updatePrefsNewTags:newTags:というメソッドを使います。…私は最初にこのメソッドを見たときわけがわかりませんでした。newTagsという名前が2回でてきてどっちがどっちだかさっぱりでした。幸い、仮引数名がoldTagsとnewTagsだったのでわかりましたが、これはちょっとおかしいんじゃないかな…

3. ライセンスが不明

そして3つ目の問題。Google Codeのプロジェクトページにはしっかりと"Apache License 2.0"と書かれているのに、OpenMeta.mでは一番上の目立つところに"MIT license"と書かれています。まあ確かに両者は似た性質を持っていますが、それでも同一ではありません。

…とまあいろいろと挙げちゃいましたが、これはOpenMetaそのものの問題ではなくそのためにIronicが用意したライブラリの問題です(OpenMetaそのものの問題についてもIronicのフォーラムで議論されているようですが… それについては今後書くかもしれないです)。多くのデベロッパに採用してほしいなら、この辺はちょっと修正してもらいたいところです。

2009-01-25

CocoaアプリケーションからOpenMetaによるメタデータを操作する

OpenMetaプロジェクトで公開されているOpenMetaクラスを使うのが簡単。ライセンスはApache License 2.0。

今のところ全部クラスメソッド。ファイルを指定するにはNSURLを使う。

タグの追加
[OpenMeta addUserTags:tags url:url];
タグの削除
[OpenMeta clearUserTags:tags url:url];

こんな感じで簡単。第一引数のtagsはNSStringを要素に持つNSArray。タグ以外の他のメタデータについても専用のメソッドが用意されているし、NSDictionaryを使って一括して扱うこともできる。

2008-11-07

PyObjCを使ってみた

先月公開したMixiMeは、PyObjCを使って作ったものです。PyObjCってのはObjective-CとPythonを結ぶブリッジの役割を担っていて、これを使うとCocoaアプリケーションをPythonで書けるようになります。うれしいことに、PyObjCはLeopardで標準搭載されていて、Xcodeからも簡単に使うことができる。

もちろん、1つのCocoaアプリケーションの中でObjective-CのコードとPythonのコードを共存させることもできる。実際にMixiMeでは、日記をmixi側に送信する部分はPythonで書いてるけど、パスワードをキーチェーンに保存したりする部分はObjective-Cで書いてある。PythonオブジェクトをCocoaオブジェクトのように扱うこともできるので、両方の言語のコードで上手く連携して作業することができる。

Pythonコード中のIBOutletなインスタンス変数もちゃんとInterface Builderで認識してくれるし、かなり便利。

2008-10-13

ディスプレイの解像度を得る

ディスプレイの解像度を(dpiで)取得しようと思ったんだけど、なんかそれっぽいAPIがない。CocoaもCore Graphicsにもない。ググってみても、なかなか見当たらないと思ったら…。ADCのTechnical Q&Aに載ってました:How can I programmatically determine the DPI of the current video mode?。

読んでみると、ディスプレイの物理的なサイズ(mm)をIOKitで得て、スクリーンのサイズ(pixel)からdpiを求めるという、なんとも言えない荒技にでてます。解像度を得るためだけにIOKitをリンクするのはなんか躊躇ってしまう。ていうかこういうのって単一のAPIとして提供さるもんではないんでしょうかね…。

2008-09-07

たのしいCocoaプログラミング Leopard対応版

HMDTの木下さんの新しい本、たのしいCocoaプログラミング[Leopard対応版]が出ていました。前にこの本のTiger版を読んだのですが、そのときに気づいたのがプログラミング初心者でも抵抗なく読めるところ。今までのCocoa入門本だと、Cの知識を既に持っていることを前提としているものがほとんどだったのに、たのココではCの説明も(必要なところだけ)本の中に含んでいて、前提知識なしで読み進められるので、プログラムを書いたことのない人にはピッタリなんじゃないかなと思いました。そして何より軽かった(内容がじゃなくて、体重計に置いたとき)。

Leopard対応版はまだ買っていませんが、LeopardではInterface Builder周りが完全に新しくなったので、そのためだけにも買う価値はあるかも。もうだいぶ慣れたとはいえ、まだまだ戸惑うし。

2008-08-23

メニューアイテム内のビューはキーボード入力を受け付けない

LeopardからはNSMenuItemにsetView:メソッドが追加されて、任意のNSViewをメニューに追加できるようになりましたが、ここで1つはまりました。

メニューアイテムにNSTextFieldを設定してみたら、テキストフィールドは表示されるものの、テキスト入力ができない。そういう仕様なんだろうか、と思ってリファレンスを覗いてみても何も書かれていない…。と思ったら、Application Menu and Pop-up List Programming Topics for Cocoa : View in Menu Itemsにしっかりとkeyboard events are not supportedって書かれてました。だめじゃん。メニュー内でテキストフィールドを使いたければ、これまで通りウインドウを生成して偽メニューでがんばるしかないのかも。がっくし。

2008-04-02

Image Kit使ってみた

ちょっとIKImageBrowserViewが使ってみたくてImage Kitをいじってみた。IBのライブラリパネルからImage Kitを選んでImage Browser Viewをぺったんこすればはい完成。すばらしい。

ただ、IKImageBrowserViewは背景が白色なのでHUD Windowに貼付けるとちょっとダサい。というわけで背景を透明にしたいんですが、リファレンスを眺めてもそれらしきメソッドが見当たりません。でもImage Kitをclass-dumpしてみると、setBackgroundColor:っていうビンゴなメソッドが見つかったので、これに[NSColor clearColor]みたいな透明色を渡してあげれば一丁前に仕上がります。

あと、IKImageBrowserViewにはズームのためのスライダをつけるのがお約束ですが、これもやっぱりHUD Windowの上にそのまま載っけるとアレなので、格好良くいたしましょう。さっきdumpした中身を眺めると、IKGraySliderっていうこれまたわかりやすい名前のクラスが見つかるので、IBからスライダのクラスをIKGraySliderに設定すればHUDにピッタリなスライダが出来上がります。

このIKImageBrowserView、URLを渡すと自動的に画像を読み込んでくれたりして便利なんですが、今のところiPhotoのようなマルチタッチ操作には対応していないようで、そこは残念。これは自前で実装しろってことなのかな。

2006-09-01

あー、ガベージコレクションよ、早く来い

今日、「スレッドインスペクタ」が原因でThousandがクラッシュするらしい、と名取さんから連絡をいただきました。スレッドを開こうとするとクラッシュするらしい。クラッシュログも送ってくださったわけなんですが、どうもNSURLDownload絡みのところで落ちてるらしい。よく調べると解放済みのオブジェクトにメッセージを送ろうとしてたらしい。

NSURLDownloadには、3つのデリゲートメソッドがある。次の3つね。

  1. - download:decideDestinationWithSuggestedFilename:
  2. - download:didCreateDestination:
  3. - downloadDidFinish:

デリゲートオブジェクトには、これらのメソッドが順に呼び出されるわけです。ていうかそうだという前提でコーディングしてたわけなんですよ。ところがですね、僕はNSURLDownloadをT2ThreadProcessingの- processThread:appendingIndex:メソッドの中で使ってたんですが、このメソッドはスレッドを1回開く時に2回呼ばれるんですよ。検証してないけど、多分ログを取得する前と後で1回づつ読んでるんでしょうね。で、そうなると先ほどの前提が崩れてしまい、運が悪いと次の順番に呼び出されてしまうわけです。

  1. - download:decideDestinationWithSuggestedFilename: // 1回目の呼び出し
  2. - download:didCreateDestination: // 1回目の呼び出し
  3. - download:decideDestinationWithSuggestedFilename: // 2回目の呼び出し
  4. - download:didCreateDestination: // 2回目の呼び出し
  5. - downloadDidFinish: // 1回目の呼び出し
  6. - downloadDidFinish: // 2回目の呼び出し

こうなると、話がややこしくなる。実は、- download:decideDestinationWithSuggestedFilename:の中であるオブジェクトをretainして、- downloadDidFinish:の中でreleaseしてたんです。でも上の順番で呼び出されてしまうと、最初にretainされたオブジェクトはどこからも参照されなくなり、2回目にretainされたオブジェクトも最後のメソッドが呼ばれる段階ではすでに解放済みなわけです。そしてここで解放済みオブジェクトにメッセージを送ろうとして、クラッシュ。ずいぶんと初歩的なミス

実はこのバグ、v0.1.xだけで発生する問題。v0.2では看板画像の表示を実装する際にこの部分を書き換えたから問題無し。チェックしたらメモリリークがいくつかあったけど、開いた瞬間にクラッシュなんてことはない。でも一応v0.2.1を出しといた。

Javaとかにあるガベージコレクション、よくわからないんだけど、これがあればこういうミスを防げるんでしょうかね。Objective-CもLeopardでサポートされるらしいですから、待ち通しですよ。G4で動くならば。

2006-08-30

「スレッドインスペクタ for Thousand」を公開したわけですが

昨日、Thousand用プラグイン「スレッドインスペクタ」を公開しました。名前のまんまの機能です。インストールすると表示中のスレッドの情報をパネルに表示することが出来るようになります。ついでに板のローカルルール表示機能もつけました。

で、公開直後、「Tigerでローカルルール表示できねーよ!」って怒られたわけです。このプラグインでは、板のhead.txtをWebViewに読み込ませているわけなんですが、お話を聞くとそのWebViewがhead.txtをHTMLとしてパースせずにそのまま表示してしまったようなんです。

head.txtはサーバ側からtext/plainとして送り出されているので、この挙動は正しいわけなんですが、僕の環境(Panther、10.3.9)ではこいつをHTMLとしてレンダリングしてくれていたわけなんですよ。だからそのままリリースしたらTigerではダメだったわけです。

試しにSafari 1.3.2でhead.txtを開いてみると、やっぱりHTMLとしてレンダリングされますよ。だからWebViewはサーバ側が送り出すContent-Typeを無視するもんだと思ったんですけど、Tigerのは違うんですね。しょうがないから一旦head.txtをNSURLDownloadで保存して- loadHTMLString:baseURL:で読み込ませることにした。

で、結局2時間半後にバージョン0.1.1をリリースする羽目になってしまったわけ。

2006-08-19

「あぼーんフィルタ for Thousand」公開。

えーと、先日のうぃ〜ラブ団子を改良して、任意のキーワードを含むレスを非表示にするようにしてみた。名前も「あぼーんフィルタ for Thousand」に。ダウンロードはThousand Additionsからどうぞ。abonefilterってのをクリックすればダウンロードできる。

フィルタの対象となるキーワードは複数指定することが可能。入力フィールドに半角カンマ区切りで入力するだけ。んー、簡単。

そのかわり、カンマを含むキーワードは指定できない。区切りと見なされちゃうからな。その辺は改良の余地あり。今回はバージョン0.1ってことにする。