2

メインメニュー(MainMenu.xib)に「ワードラップ」というタイトルのNSMenuItemがあります。その値は、XIBでもインスタンス化されている、共有ユーザーのデフォルトコントローラーにバインドされています。また、選択すると次のアクションが送信されます。

- (IBAction)toggleWordWrap:(id)sender {
    NSUserDefaultsController *ctrlr = [NSUserDefaultsController sharedUserDefaultsController];
    if ([[[ctrlr values] valueForKey:@"wordWrapIsEnabled"] boolValue]) {
        // turn on word wrap
    } else {
        // turn off word wrap
    }
}

アプリデリゲートの+initializeメソッドでは、標準ユーザーのデフォルトにデフォルト値を入力します。

+ (void)initializeDefaults {
    NSDictionary *defaults = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:NO], @"wordWrapIsEnabled",
                             // etc.
                             nil];
    NSUserDefaultsController *ctrlr = [NSUserDefaultsController sharedUserDefaultsController];
    [ctrlr setInitialValues:defaults];
}

私の問題は、NSMenuItemの状態がユーザーのデフォルトと同期していないことです。何が起こるかのタイムラインは次のとおりです。

アプリの起動:

  • ワードラップメニュー項目がチェックされていません
  • wordWrapIsEnabledいいえです
  • ワードラップはオフです

ワードラップが初めて選択されたとき:

  • チェックされたワードラップメニュー項目
  • wordWrapIsEnabledNO (BZZZT WRONG)
  • ワードラップがオフです(BZZZT WRONG)

2回目のワードラップが選択された場合:

  • ワードラップメニュー項目がチェックされていません
  • wordWrapIsEnabledはいです(BZZZTが間違っています)
  • ワードラップがオンになっています(BZZZTが間違っています)

フリップフロップ広告を無限に繰り返します。

プロジェクトににアクセスするものが他にないことを確認しましたwordWrapIsEnabled。セレクターの呼び出しとwordWrapIsEnabledバインディングを介したの設定の間に競合状態が発生する可能性はありますか?バインドされた値が最初に設定されると想定してきました。

4

2 に答える 2

11

stateバインドされた(または) プロパティを持つメニュー項目をクリックすると、valueメニュー項目はそのアクションをトリガーしバインドされた値を反転します。また、これら 2 つの操作の順序は保証されていないようです。Cocoa Builder の次のスレッドを参照してください。

ありがとうございます。プロジェクトにいくつかの変更を加えたため、完全にはわかりませんが、コンパイルを開始したときに発生し始めたため、これは 10.5 SDK のバグと見なすことができると思います。Tiger を対象とした (ほぼ) 同じプロジェクトは、 それがボタンであるか menuItem であるかに関係なく、target-action が実行される前に常にバインドされた値を変更しました。どうやら、この一貫性は Leopard では壊れているようです。それを確認するためにいくつかのテストを行った後、バグレポートを投稿する場合があります。

メニュー項目がバインドされた値を自動的に反転するべきではないという、関連するRadar バグ レポートもあります。これはおそらくあなたの質問への回答としては遅すぎますが、次回誰かがこの問題に遭遇したときに役立つことを願っています.

于 2011-04-08T07:23:41.837 に答える
2

NSMenuItem の共有ユーザー デフォルトに Cocoa バインディングを使用している場合は、NSMenuItem のセレクターの使用を停止し、代わりにキーと値の監視を使用して、値がいつ変更されたかを判断し、適切に対処する必要があります。

この例ではuseTransparency、NSMenuItem がバインドされている値の名前を取得しています。コントローラーの init で、この値の更新を受け取るように登録します。

    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];

    [userDefaults addObserver:self
                   forKeyPath:@"useTransparency"
                      options:NSKeyValueObservingOptionNew
                      context:NULL];

その後、observer メソッドを実装します。

-(void)observeValueForKeyPath:(NSString *)keyPath
                     ofObject:(id)object
                       change:(NSDictionary *)change
                      context:(void *)context
{
    NSLog(@"KVO: %@ changed property %@ to value %@", object, keyPath, change);

    if ([keyPath compare:@"useTransparency"] == NSOrderedSame)
    {
        BOOL isTransparent = [[change valueForKey:@"new"] boolValue];
        [self setTransparency:isTransparent];
    }
}

特に、私は NSMenuItem のセレクターをまったくバインドしません。キーと値の監視に任せるだけです。セレクターにバインドすると、値が変更されるタイミングとセレクターが起動されるタイミングを推測しようとするという問題に遭遇します。2 つを混在させるのではなく、バインディング システムを使用するだけで、この問題全体を完全に回避できます。

于 2012-11-28T20:06:13.827 に答える