SSブログ

PaTrash2.0を作る - その10 [プログラミング]

なかなか進まないPaTrash2.0。でも、あともうちょっと。
今日は前回の続きで、システム環境設定アプリ用のペインを書くためのノウハウ集のその2である。けっこう悩ましい問題がある。

7.4.4  メニューバー

ペインのユーザインターフェイス要素としてメニューバーは使えない。もちろん、メニューバーにメニューを追加することはできるけど、ペインを開くと副作用的にメニューが追加されるという、非標準的な動作になる。

そう言う動作はjavaやWindowsではありえるけど、Macでは伝統的にメニューバーに並ぶ項目はアプリケーションごとに固定される。アプリの状態によっては意味をなさない項目も、Macではdim表示(文字が薄くなって選択できない状態)になるだけで、無くなったり位置が変わったりはしない。これはユーザが選択するときにメニューのタイトル文字列と同時にその位置も手がかりにするからである。これは古い「Macintosh Human Inteface Guildeline」にはっきりと書かれていた。Mac OS Xのガイドにはなくなっているが、重要である。

それ以外のユーザーインターフェイス要素は問題なく使える。

7.4.5  ランタイムの共有

もうひとつの問題はObjective-Cのランタイムが共有されるということ。

普通のアプリを作るときにFoundationフレームワークのクラスに対して、カテゴリを使ってメソッドを追加するということをときどきするけど、そのメソッド定義が衝突する可能性がある。メソッド名はふつう読みやすい直観的な名前が選ばれる。カテゴリで拡張したとき、たまたま同じメソッド名を使う可能性がありえる。ガイドでは汎用フレームワークのクラスに「カテゴリでメソッドを追加するな」となっている。まあ、それが正しいだろうけど、カテゴリって便利なのでついうっかりやってしまう、ということもあるだろう。気をつけなければならない。

7.4.6  名前空間の共有

同じ名前を持つクラスが他の環境設定ペインで使われていると衝突してしまう。これはさっきの話のランタイムが共有されていることから起こる問題のひとつである。C++などの言語では名前空間を分割する機能が備わっているけど、Objective-Cではそのためのメカニズムが提供されていない。これはプラグインを作るとき、いわば赤の他人がつけた名前からお互いのコードを守る簡単な手段がない、ということになって非常に問題である。

Objective-Cの場合(もちろんCでも同じだけど)、名前の付け方を工夫するしかない。AppleのGuideにはバンドル識別子に使われる逆ドメイン名からピリオドを除いた文字列をクラス名に接頭辞としてつけろ、と書いてある。そうすると長くなりすぎるので
#define SoundPref ComApplePreferenceSoundPref
#define AlertController ComApplePreferenceSoundAlertController
#define MicrophoneController ComApplePreferenceSoundMicrophoneController
みたいにしろ、となっている。いっけんこれで良さそうだけど、InterfaceBuilderとの関係が非常に気になってしまう。

どういうことかというと、例えばペインのヘッダをこのようにしたとする。
#define PaTrashPanePref     neJpDecafishPaTrashPanePref    

@interface PaTrashPanePref : NSPreferencePane {
    IBOutlet NSTableView        *tview;
    IBOutlet PTArrayController  *acont;
    ....
これはAppleのGuideにあったそのままのやりかたである。これをInterfaceBuilderでFile's Ownerに指定する。するとInterfaceBuilderではソースに書いてあったアウトレットが表示されない。こんなふうに。

0804ibfilesowner.png

つまり、InterfaceBuilderは#defineされた長い名前のクラスを知らない、ということである。ためしに#defineを無視して(ソースを変更せずに)短い名前をInterfaceBuilderで使って見るとこのようにアウトレットが表示される。

0804ibfilesowner2.png

つまり、InterfaeBuilderはプリプロセス(cpp)後を見ているのではなく、ソースの字面だけを頼りにクラス定義やそのインスタンスの存在を確認していることがあきらかである。

このようなInterfaceBuilderとソースとの関係と、名前空間は別物なのでこれ自身は問題ないのかもしれない。しかし問題ないことを保証するメカニズムが提示されているわけではないので、思いもかけないところで問題が出る可能性がないとは言えない。少なくとも精神衛生上よろしくない。

Cocoa/Objective-Cが名前空間をサポートしないのでイマイチという話をときどき読むことがあるけど、どのみちC++のnamespaceも衝突しないことを保証するものではない。名前空間の問題はふだんあまり気にしないんだけど、問題が出たときには案外悩ましい。

7.4.7  システム環境設定ペインのデバグ

システム環境設定ペインは単独のアプリではなくプラグインなのでそのままデバグできない。プラグインのデバグ用にXcodeではプラグインを読み込む側のアプリを指定して実行できるようにする。

そのためにはXcodeの「プロジェクト」メニューで「新規実行可能ファイル...」を選択してアプリを指定する(今の場合「システム環境設定アプリ」を選択する)。その実行可能ファイルをデバッガで呼ぶことでプラグインをデバグできる。もちろんソースはプラグインが実行されている時点でしか表示できない。

ところが、システム環境設定ペインのデバグにはもう一工夫必要になる。システム環境設定ペインは決まった場所にないと読み込まれないので、通常のXcodeの設定ではシステム環境設定アプリを立ち上げてもアイコンが表示されないのでペインを読み込むことができない。

そこで、Xcodeの設定を変更してデバグ用の「ビルドプロダクトのパス」をペインのインストール先に指定する。つまりXcodeでターゲットを編集して(「プロジェクト」メニューの「アクティブターゲットを編集...」)「ビルドの場所」の「構成ごとのビルドプロダクトのパス」を自分のライブラリフォルダのPreferencePanesディレクトリに書き換える。

0804buiilddir.png

これはCONFIGURATION_BUILD_DIRスイッチを指定することになる。デフォルトでは$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)となっていてこれはプロジェクトフォルダのbuild/Debug/になる。これはXcodeを使う人にはおなじみのパスだろう。Release側は書き換えないほうがいい。

こうしておいて、デバッガを呼ぶと「システム環境設定」アプリが立ち上がって、スイッチの値が読み込まれてデバッガはソースを表示するようになる。

デバグが終わったらDebug構成のプロダクト(~/Library/PreferencePanesにあるペインのファイル)を消しておくことを忘れないようにしないといけない。
nice!(0)  コメント(0)  トラックバック(0) 

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

献立08/04献立08/05 ブログトップ

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。