Привязка значения NSMenuItem к BOOL

У меня возникли проблемы с привязкой «значения» NSMenuItem к BOOL.

Я упростил задачу до этого:

1) Пункт меню должен вызывать метод действия, который изменяет значение BOOL, в противном случае он не работает (т. е. если NSButton вызывает метод, который изменяет значение BOOL, тогда элемент меню выиграл не обновляюсь)

2) Даже если метод действия делает BOOL константой (т.е. enabled = YES), «значение» пункта меню все равно меняется.

Любые идеи? Я весьма озадачен!

Вот код:

MenuBindings_AppDelegate.h

#import <Cocoa/Cocoa.h>

@interface Menu_BindingsAppDelegate : NSObject <NSApplicationDelegate> 
{   
   BOOL foo;
}

- (IBAction)toggle:(id)sender;
- (IBAction)makeYes:(id)sender;

@property BOOL foo;

@end

Menu_BindingsAppDelegate.m

@implementation Menu_BindingsAppDelegate

@synthesize foo;

- (IBAction)toggle:(id)sender
{
   [self setFoo:!foo];
}

- (IBAction)makeYes:(id)sender
{   
   [self setFoo:YES];
}

@end

В моем пере у меня есть кнопка, связанная с действием -makeYes:, и пункт меню, связанный с действием -toggle:. Привязка «значение» пункта меню привязана к атрибуту «foo» делегата приложения.

Спасибо.


person chrisgoyal    schedule 11.02.2010    source источник


Ответы (1)


Cocoa Bindings использует наблюдение за ключом и значением (KVO) для получения уведомлений об изменениях в объектах модели. Чтобы изменение модели (ваше значение BOOL) было замечено наблюдателями, включая любые представления, использующие привязки, необходимо обновить модель с помощью Key-Value Coding. Если вы просто установите значение ivar напрямую, KVO-уведомления отправляться не будут.

Вы можете либо реализовать средства доступа KVC самостоятельно, либо объявить свойство и использовать ключевое слово @synthesize в своей реализации, чтобы компилятор создал для вас совместимые средства доступа.

Вот как вы могли бы реализовать KVC-совместимые средства доступа:

//YourModel.h
@interface YourModel : NSObject
{
    BOOL enabled;
}
- (BOOL)enabled;
- (void)setEnabled:(BOOL)flag;
@end

//YourModel.m
@implementation YourModel
- (BOOL)enabled
{
    return enabled;
}
- (void)setEnabled:(BOOL)flag
{
    enabled = flag;
}
@end

и вот как вы могли бы сделать то же самое, используя синтаксис свойства Objective-C 2.0:

//YourModel.h
@interface YourModel : NSObject
{
    BOOL enabled;
}
@property BOOL enabled;
@end

//YourModel.m
@implementation YourModel
@synthesize enabled;
@end

Затем вы можете позвонить [yourModel setEnabled:YES], и все зарегистрированные наблюдатели KVO (включая привязку к вашему меню) будут проинформированы об изменении.

В качестве альтернативы вы можете вызвать yourModel.enabled = YES, который будет использовать соответствующие средства доступа KVC, если они доступны.

Я загрузил пример проекта, чтобы продемонстрировать, как это делается.

person Rob Keniger    schedule 11.02.2010
comment
Спасибо за предложение. Я пытался использовать как willChangeValueForKey:/didChangeValueForKey:, так и поведение @property/@synthesize, но все равно получаю странные результаты... - person chrisgoyal; 11.02.2010
comment
Можете ли вы опубликовать свой код? Вам не нужно использовать will/didChangeValueForKey: если вы реализуете средства доступа, совместимые с KVC. - person Rob Keniger; 11.02.2010
comment
Ничего, я понял проблему. Когда вы нажимаете на пункт меню, его значение автоматически переключается. Не понял, что ... спасибо! - person chrisgoyal; 12.02.2010
comment
Да, это потому, что привязка двусторонняя. Я могу понять, почему это может сбивать с толку. - person Rob Keniger; 12.02.2010