以下是设置:我有一个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
无效。
答案 0 :(得分:4)
绑定的KVO流程不是正交的;绑定不是属性,它是属性的引用。这是记住绑定如何工作的简写:
因此,当带有绑定的视图处理事件时,它需要将更改传播到其绑定引用自身的属性。
这是你的代码可能是什么样子,使用实用程序方法通过绑定来繁重地传播更改:
- (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
并留意您感兴趣的绑定。如果有任何值变换器,请跟踪observableController
和keyPath
(以及options
字典) 。更新控件的值时,您需要发送
[observableController setValue:newValue forKeyPath:keyPath];
使用新值更新控制器。关键值观察是一条单行道,在绑定中,控制是观察者。