在设置绑定属性时观察NSUserDefaultsController不工作

时间:2010-01-25 11:00:43

标签: objective-c cocoa macos imagekit ikimagebrowserview

以下是设置:我有一个IKImageBrowserView的子类,其zoomValue属性绑定到共享VFBrowserZoomValue中的键NSUserDefaultsController。我有一个NSSlider,其value绑定绑定到同一个密钥。

这非常适合从滑块更改浏览器的zoomValue

我正在尝试在-magnifyWithEvent:子类中实现IKImageBrowserView,以允许在触控板上使用捏合手势缩放浏览器。

这是我的实施:

-(void)magnifyWithEvent:(NSEvent *)event
{
  if ([event magnification] > 0) {
    if ([self zoomValue] < 1) {
      [self setZoomValue: [self zoomValue] + [event magnification]];
    }
  } 
  else if ([event magnification] < 0) {
    if ([self zoomValue] + [event magnification] > 0.1) {
      [self setZoomValue: [self zoomValue] + [event magnification]];
    }
    else {
      [self setZoomValue: 0.1];
    }
  }
}

这会正确更改浏览器的zoomValue。问题是NSUserDefaults未使用新值更新。

在应用程序的其他地方,我有一个-observeValueForKeyPath:ofObject:change:context:的实现,它会观察浏览器的zoomValue。如果我在该方法中记录浏览器缩放的值,滑块的值和默认值,我看到浏览器的zoomValue尚未被推入NSUserDefaults并且滑块未更新。

我尝试围绕-magnifyWithEvent:方法调用-{will,did}ChangeValueForKey无效。

3 个答案:

答案 0 :(得分:4)

绑定的KVO流程不是正交的;绑定不是属性,它是属性的引用。这是记住绑定如何工作的简写:

  • KVO用于传达从模型到控制器的变化。图。
  • KVC用于将视图中的更改传达给控制器&amp;模型。

因此,当带有绑定的视图处理事件时,它需要将更改传播到其绑定引用自身的属性。

这是你的代码可能是什么样子,使用实用程序方法通过绑定来繁重地传播更改:

- (void)magnifyWithEvent:(NSEvent *)event
{
  if ([event magnification] > 0) {
    if ([self zoomValue] < 1) {
      [self setZoomValue: [self zoomValue] + [event magnification]];
    }
  } 
  else if ([event magnification] < 0) {
    if ([self zoomValue] + [event magnification] > 0.1) {
      [self setZoomValue: [self zoomValue] + [event magnification]];
    }
    else {
      [self setZoomValue: 0.1];
    }
  }

  // Update whatever is bound to our zoom value.
  [self updateValue:[NSNumber numberWithFloat:[self zoomValue]]
         forBinding:@"zoomValue"];
}

有点不幸的是,ImageKit需要使用@"zoomValue"来引用IKImageBrowserView的缩放值绑定,AppKit中的大多数绑定都有自己的全局字符串常量,如NSContentBinding

这是通用实用方法通过绑定传播更改:

- (void)updateValue:(id)value forBinding:(NSString *)binding
{
  NSDictionary *bindingInfo = [self infoForBinding:binding];

  if (bindingInfo) {
    NSObject *object = [bindingInfo objectForKey:NSObservedObjectKey];
    NSString *keyPath = [bindingInfo objectForKey:NSObservedKeyPathKey];
    NSDictionary *options = [bindingInfo objectForKey:NSOptionsKey];

    // Use options to apply value transformer, placeholder, etc. to value
    id transformedValue = value; // exercise for the reader

    // Tell the model or controller object the new value
    [object setValue:transformedValue forKeyPath:keyPath];
  }
}

实际上,应用占位符,价值变换器等是留给读者的练习。

答案 1 :(得分:0)

我担心这是预期的行为,请参阅绑定文档的this FAQ section。你需要手动推送它。

答案 2 :(得分:0)

当您创建一个与绑定兼容的控件(或者,在您的情况下,子类化一个)时,由控件在其值发生变化时通知控制器。所以,你要做的是覆盖

- (void)bind:(NSString *)binding toObject:(id)observableController withKeyPath:(NSString *)keyPath options:(NSDictionary *)options

并留意您感兴趣的绑定。如果有任何值变换器,请跟踪observableControllerkeyPath(以及options字典) 。更新控件的值时,您需要发送

[observableController setValue:newValue forKeyPath:keyPath];

使用新值更新控制器。关键值观察是一条单行道,在绑定中,控制是观察者。