【问题标题】:State of NSMenuItem bound to boolean in NSUserDefaults not staying in syncNSMenuItem 的状态绑定到 NSUserDefaults 中的布尔值不保持同步
【发布时间】:2011-02-25 05:24:31
【问题描述】:

我的主菜单 (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
    }
}

在我的应用代理的 +initialize 方法中,我使用默认值填充标准用户默认值:

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

我的问题是我的 NSMenuItem 的状态与我的用户默认设置不同步。以下是发生的时间线:

应用发布:

  • Word Wrap 菜单项未选中
  • wordWrapIsEnabled
  • 自动换行关闭

第一次选择自动换行:

  • 选中自动换行菜单项
  • wordWrapIsEnabled 没有 (BZZZT 错误)
  • 自动换行已关闭(BZZZT 错误)

第二次选择自动换行:

  • Word Wrap 菜单项未选中
  • wordWrapIsEnabled(BZZZT 错误)
  • 自动换行开启(BZZZT 错误)

无限重复触发器。

我已检查以确保我的项目中没有任何其他内容可以访问wordWrapIsEnabled。在调用选择器和通过绑定设置wordWrapIsEnabled 之间是否存在竞争条件?我一直假设首先设置绑定值。

【问题讨论】:

    标签: nsuserdefaults cocoa-bindings nsmenuitem


    【解决方案1】:

    当您单击具有绑定state(或value)属性的菜单项时,菜单项会触发其操作翻转绑定值。而且这两个操作的顺序好像不能保证,见下面thread on Cocoa Builder

    谢谢,我不确定 因为我在我的 项目,但我认为这可以 被认为是 10.5 sdk 的错误,因为 当我开始的时候它就开始发生了 为它编译。 (几乎)相同 以 Tiger 为目标的项目 总是改变界限值 目标动作被执行之前,不管它是否是 按钮或菜单项。显然这 一致性已被打破 豹。我可能会在之后发布错误报告 一些测试来确认它。

    还有一个相关的Radar bug report 说菜单项不应该自动翻转绑定值。回答您的问题可能为时已晚,但希望下次有人遇到此问题时会有所帮助。

    【讨论】:

    • 非常有帮助,谢谢。一百万年后我永远不会猜到状态会自动翻转。
    • 噢!在找到它之前,我测试了很多方法来正确切换值。有时增加的懒惰会阻止编写无意义的代码;)
    【解决方案2】:

    当您使用 Cocoa 绑定到 NSMenuItem 的共享用户默认值时,您应该停止使用 NSMenuItem 的选择器,而是使用键值观察来确定值何时发生变化,然后采取适当的行动。

    在此示例中,我有一个 NSMenuItem 绑定到的 useTransparency 值名称。在我的控制器的初始化中,我注册以接收对此值的更新:

        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 绑定选择器——我只是让键值观察来完成这项工作。如果您绑定到选择器,您会遇到尝试猜测值何时更改与选择器被触发的问题。完全避免整个问题,只需使用绑定系统而不是两者的混合。

    【讨论】:

      猜你喜欢
      • 2021-07-22
      • 1970-01-01
      • 1970-01-01
      • 2011-08-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-19
      • 1970-01-01
      相关资源
      最近更新 更多