アーカイブ

Archive for 2009年8月

アプリケーションパッケージ名とアプリケーションメニューのローカライズ方法は異なる

OS Xのアプリケーションパッケージの名前をローカライズした所、Finder上では正常にローカライズされているのに、起動後のアプリケーションメニューのタイトルがローカライズされないという現象に遭遇しました。
そこでよくよくドキュメントを調べてみたら、パッケージ名とメニュータイトル及びアバウトダイアログでは、参照している情報が異なる事に気がつきました。
正常にローカライズできなかったのは、アプリケーションパッケージに必要なCFBundleDisplayNameだけが設定してあり、メニュータイトルに必要なCFBundleNameが抜け落ちていた事が原因です。

アプリケーションパッケージの場合

  • Info.plistにCFBundleDisplayNameを追加する。値は英語版の名前で良い。
  • 言語別のInfoPlist.stringsでCFBundleDisplayNameをローカライズする。
  • Info.plistにLSHasLocalizedDisplayNameを追加する。値は真。

LSHasLocalizedDisplayNameはiPhoneでは見かけないキーですが、ドキュメントによるとCFBundleDisplayNameの検索速度が向上する事になっています。

メニュー及びアバウトダイアログの場合

  • Info.plistにCFBundleNameを追加する。値は英語版の名前で良い。
  • 言語別のInfoPlist.stringsでCFBundleNameをローカライズする。

今回のトラブルは、こちらが抜けている事が原因でした。

広告
カテゴリー:開発 タグ: ,

NSMenuItemのenabled以外の属性の更新

Cocoaでメニューの有効・無効を制御する場合、レスポンダ側にNSMenuValidationを実装します。
対象になるメニューに対して、レスポンダチェーンのどこかでvalidateMenuItem:がYESを返した場合は有効、それ以外の場合は無効に設定されます。

類似の処理として、メニューアイテムにチェックマークを付けたり、タイトルを修正したい事があります。
validateMenuItem:にはメニューアイテムも渡ってくるので、有効を返す前にメニューアイテムにチェックマークを設定してやれば良いかと思いましたが、問題がある事が判りました。
有効・無効の場合とは異なり、メニューアイテムその物を変更してしまっているので、別のタイミングで明示的にチェックマークを外さない限り、マークが付いたままになります。
レスポンダチェーンがどこも反応しない場合に、チェックマークが無い状態に戻ると勘違いしていたのです。

ここを正しく実装するためには、チェックマークを付けたりタイトルを修正する可能性のあるメニューアイテムはすべて、アプリケーションデリゲートのvalidateMenuItem:で初期状態に戻す必要があるという事です。
アプリケーションデリゲートがレスポンダチェーンから外れる事は無いので、必ずメニューを更新する事ができます。

カテゴリー:開発 タグ: ,

NSTableViewを参照オブジェクトのフィールドでソートする

NSTableViewをカラムヘッダクリックによってソートする場合、デリゲートでtableView:sortDescriptorsDidChange:を受けて、データソースをソートします。
この時NSSortDescriptorの配列が渡ってくるのですが、ここにはソートに使うカラム名と順序が入っています。
オブジェクトが一つでないのは、いくつかのカラムをクリックした場合にそのソート履歴を残しておいて、比較結果が同一の場合の第二比較条件に使うためです。
例えば名前カラムの次に年齢カラムをクリックした場合、まず年齢でソートが行われますが、同一年齢の要素はさらに名前でソートされます。

NSTableViewがNSSortDescriptorを生成する時に使うカラム名は、NSTableColumnにsetSortDescriptorPrototype:で設定しておきます。
通常データソースはNSMutableArrayに詰め込まれたオブジェクトの配列で、NSSortDescriptorが指定するカラム名をキーバリューコーディングで解決してソートを行います。

ここで、次のようなケースを考えます。
テーブルに住所録が表示されていて、そのカラムに会社名が存在するケースです。
モデルは、以下のようになります。

@interface Organization : NSObject {
    NSString *name;
    NSString *address;
}

@interface Person : NSObject {
    NSString *name;
    NSInteger *age;
    NSString *address;
    Organization *organization;
}

Personのorganizationはnilの場合もあり、その場合は無所属です。
ここでNSTableViewに住所録を表示したとして、カラムに組織名があった場合、そのNSSortDescriptorのキーは次のように指定する事ができます。

[[NSSortDescriptor alloc] initWithKey:@"organization.name" ascending:YES selector:@selector(compar:)];

organizationのnameがnilの場合や、organizationがnilの場合でも正常に動作します。

キーバリューコーディングにおけるピリオドを使った参照オブジェクトの指定は、tableView:objectValueForTableColumn:row:を実装する時にも使えると思います。

カテゴリー:開発 タグ: ,

Interface BuilderでビューのAutosizingが設定できない時

Interface Builderで、ビューのAutosizingを設定できない事があります。
この場合、コントロールが無反応になります。
最初は理由が良く判らなかったのですが、次の条件で設定不可になるようです。

  • 対象のビューがxibのトップレベルオブジェクトの一つ。
  • 対象のビューにSimulated Inteface Elementsが一つでも設定されている。

ポイントは後者です。一旦Simulated Inteface ElementsをNoneにしてやればAutosizingを設定できるので、その後に再設定すれば良いです。

カテゴリー:開発 タグ:

UINavigationControllerのUIToolbarサポート

iPhone 3.0になって、UINavigationControllerがUIToolbarを管理してくれるようになりました。UIToolbarを自前で管理しようとすると、UIViewControllerの管理するviewを階層化する必要があったり、その影響でUITableViewControllerが使えなくなったりと面倒な事が多かったのですが、UINavigationControllerに任せるとかなり楽になります。
具体的には、次のような事をやってくれます。

  • UINavigationBarのように、UIToolbarをUIViewControllerの管理するviewの外側で管理してくれる
    viewの階層構造が複雑化しませんし、UITableViewControllerも使えます。
  • UINavigationBarのように、UIToolbarに含まれるUIBarButtonItemをUIViewControllerの遷移に合わせて自動的に交換してくれる

概ね、UINavigationBarサポートと同等という事になります。

所がInterface BuilderでUINavigationControllerにUIToolbarを設置しようとすると、思ったように行かなかったりします。

UIBarButtonItemが設置できないように見える

Interface BuilderでUIBarButtonItemをUINavigationControllerのviewのツールバー部分にドラッグしても、ツールバー上に挿入ポイントが表示されません。しかし、そのままドロップすれば普通に挿入可能です。UIViewに自分で設置したUIToolBarの場合は挿入ポイントが表示されるので、挿入不能と勘違いしてしまいそうです。
あるいはxibの階層リストの方で、UIViewControllerの直下にUIBarButtonをドロップする事もできます。

UIControlが設置できないように見える

UIViewに自分で設置したUIToolBarの場合は、UIControl(UISegmentedControl等)を設置する事もできました。この場合、UIBarButtonItemがUIControlをラップした状態になります。所がUINavigationControllerのツールバー部分にUIControlをドロップしても、ツールバーに入れる事ができません。代わりに、UIViewControllerの管理するviewに入ってしまいます。しかし、他のUIToolBarに設置済みのUIBarButtonItemにラップされたUIControlを、UINavigationControllerのツールバーにドラッグアンドドロップする事ができます。
つまり、作業用のUIToolBarを適当なUIViewに設置して、一旦そこに用意したUIControlを移動してしまえば良いんです。

以上の話はiPhone SDK 3.0の時点ですが、遠からず改良されると思います。

カテゴリー:開発 タグ: