XCode4でのnib編集時のTarget/Actionの扱い

以前のInterfaceBuilderで使っていたテクニックが使えなくなっていた。

InterfaceBuilderではtarget/actionパラダイムで接続出来るクラスは、以下の4つのメソッドがヘッダに定義されていれば問題なく使えた。

- (id)target;
- (void)setTarget:(id)anObject;
- (SEL)action;
- (void)setAction:(SEL)aSelector;

上記の4つのメソッドの有無で、IBActionConnectionでコネクションを張れるかどうかを判断していたらしい。

XCode4でこのテクニックは使えない。代わりに以下のような手法を使う。

  1. actionセレクタを文字列で設定するメソッドを追加する

    - (void)setActionName:(NSString*)inActionName
    {
        self.action = NSSelectorFromString(inActionName);
    }
    
    - (NSString*)actionName
    {
        return NSStringFromSelector(_action);
    }
    
  2. ヘッダにtargetをIBOutletを付ける

    @property (retain) IBOutlet id target;
    
XCode4上のUIエディターで通常のconnectionとして接続する事でtargetの設定が出来きる。
  1. XCode4上でセレクタ名を設定する

“Identify Inspector”の”User Defined Runtime Attributes”に

key Path actionName
Type String
Value <selectorNameString>

と設定する。これで、nibの読込み完了時にactionが設定される。

メニューのアップデート

先日の問題の続き。

Application delegateで

- (void)applicationDidUpdate:(NSNotification *)notification
{
    [[NSApp mainMenu] update];
}

と行えば、メニューの状態をメニューバーのクリック前に随時更新する。らしい。

NSLogで挙動を見る限り、更新作業をオンタイムで行っている。

が、ここで更に問題が有った。と言うよりも、私自身の問題認識が間違っている。

NSMenuは所有するNSMenuItemが全てDisableでもNSMenu自身はDisableになる訳ではない。

そもそも、OpenStepでは、MacOSの流儀と違ってSubMenuが選択出来ないからといって、Menuを選択出来ないようにする文化が無いのかもしれない。

NSMenuItemの更新のタイミング

NSMenuItemの更新のタイミング、[NSUserInterfaceValidations validateUserInterfaceItem:(id)anItem]が呼ばれるタイミングは、マウスがNSPopupMenuをクリックした時だった。

NSPopupMenuのmenuを表示する直前に更新処理をするのは、更新処理を必要最小限にする為と思われる。

理にかなっていると思うのだが、1点マズい事がある。

menuItemが全てDisableの場合は、NSPopupMenuもDisableにする必要がある。 しかし、更新のタイミングがNSPopupMenuをクリックする時だと奇妙な挙動が起る。

ユーザーが、NSPopupMenuをクリックした瞬間に、クリックしたNSPopupMenuがDisableに変わってしまう。(1/22追記 この認識自体が間違い)

解決方法は、更新処理をNSPopupMenuをクリックした時ではなく、NSWindowDidUpdateNotificationが飛んで来た時に更新すると良いと思われる。

コードは、色々と失敗したので挫折した。

Cocoa bindingが行われているかのチェック方法

[NSObject infoForBinding:バインディング名]で確認出来る。

nilで有ればbindingがされていない。nil以外の場合はbindingに関する詳細な情報がディクショナリ形式で返ってくる。