我的主菜单(MainMenu.xib)中有一个名为“Word Wrap”的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
}
}
在我的app delegate的+initialize
方法中,我使用默认值填充标准用户默认值:
+ (void)initializeDefaults {
NSDictionary *defaults = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:NO], @"wordWrapIsEnabled",
// etc.
nil];
NSUserDefaultsController *ctrlr = [NSUserDefaultsController sharedUserDefaultsController];
[ctrlr setInitialValues:defaults];
}
我的问题是我的NSMenuItem的状态与我的用户默认值不同步。以下是发生的事情的时间表:
应用启动:
wordWrapIsEnabled
没有第一次选择Word Wrap:
wordWrapIsEnabled
不是(BZZZT WRONG) 第二次选择Word Wrap:
wordWrapIsEnabled
是YES (BZZZT WRONG) 无限重复触发器。
我已经检查过以确保我的项目中没有任何内容可以访问wordWrapIsEnabled
。通过绑定调用选择器和设置wordWrapIsEnabled
之间是否存在竞争条件?我一直在假设首先设置绑定值。
答案 0 :(得分:10)
当您单击具有绑定state
(或value
)属性的菜单项时,菜单项都会触发其操作并翻转绑定值。并且似乎无法保证这两个操作的顺序,请参阅以下thread on Cocoa Builder:
谢谢,我不是很确定 因为我做了几次改变 项目,但我认为这可以 被认为是10.5 sdk的错误,因为 我开始时就开始发生了 为它编译。 (几乎)相同 以虎为目标的项目 总是改变绑定值 执行目标操作之前 ,无论它是否为 按钮或menuItem。显然这个 一致性已被打破 豹。之后我可能会发布错误报告 一些测试来确认它。
还有一个相关的Radar bug report说菜单项不应自动翻转绑定值。对于你的问题,这可能为时已晚,但希望下次有人遇到这个问题时会有所帮助。
答案 1 :(得分:2)
当你使用Cocoa绑定到NSMenuItem的共享用户默认值时,你应该停止使用NSMenuItem的选择器,而是使用键值观察来确定值何时发生了变化,然后采取适当的行动。
在这个例子中,我有一个NSMenuItem绑定的useTransparency
值名称。在我的控制器的init中,我注册接收此值的更新:
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults addObserver:self
forKeyPath:@"useTransparency"
options:NSKeyValueObservingOptionNew
context:NULL];
然后我实现了观察者方法:
-(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的选择器 - 我只是让键值观察完成这项工作。如果绑定到选择器,则会遇到尝试猜测值何时将更改而不是选择器被触发的问题。通过使用绑定系统而不是两者的混合来完全避免整个问题。