Objective c 如何在不触发KVO的情况下设置值

Objective c 如何在不触发KVO的情况下设置值,objective-c,key-value-observing,Objective C,Key Value Observing,我使用以下代码在对象上添加KVO [self.model addObserver:self forKeyPath:@"userName" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil]; 现在我想设置用户名,如下所示。是的,它将触发KVO self.model.userName = @"tes

我使用以下代码在对象上添加KVO

[self.model addObserver:self
             forKeyPath:@"userName"
                options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
                context:nil];
现在我想设置用户名,如下所示。是的,它将触发KVO

self.model.userName = @"testUser";
但是,我想在不触发KVO的情况下设置值。怎么做?有没有像下面这样的方法可以让我这么做

[self.model setValue:@"testUser" forKey:@"userName" isSilent:YES];

如果你想这样做,你的设计就被破坏了。键值观察的要点是,有人想知道字段何时更改,以便注册通知。遵守关键价值观的关键在于,您可以选择系统的其他部分如何与您交互

听起来你是在试图绕过一些问题,你不想让别人知道某个房产的真实价值。所以他们认为他们得到了更新,但实际上,如果他们检查了财产,那么结果证明你是故意撒谎

正如你所料,Cocoa没有任何机制来支持这种黑客行为。它们是非常糟糕的做法,破坏了面向对象编程的整个结构

除了讲课,您还可以编写一个直接指向实例变量的自定义setter。所以,例如

- (void)setUserNameAndLieAboutItAsAShortSightedHack:(NSString *)newName
{
    _userName = newName;
}

在系统级别,通过创建新版本的属性setter来实现键值观察,该属性setter包含对真实setter的调用,并在外部进行适当的观察者调用。因此,避免使用真正的setter将避免通知。

核心数据实现了
setPrimitiveValue:forKey:
以允许您这样做。您可以在对象中实现相同的方法

[self.model setPrimitiveValue:@"testUser" forKey:@"userName"];

但是,在执行此操作时,应在聚合通知的上下文中,最终通过手动
willChangeValueForKey:
didChangeValueForKey:
通知观察者

您可以使用忽略标志。这和我们的文档中的想法是一样的


如果我猜测PO的意图,我猜他是在试图检测某个更高级别的状态更改,他可能会将其与一个键混为一谈。如果是这样的话,最好的建议是明确理解状态更改,并使用NSNotificationCenter或其他工具。也许更好的办法是问问PO他的意图。你能解释一下你想做什么吗?为什么有时不想触发KVO?
// update the config object with the value the user chose.
- (IBAction)valueChanged:(UISlider *)slider{
    self.ignore = YES;
    self.config.sliderValue = slider.value;
    self.ignore = NO;
}

// update the slider with the value from the config object.
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if (context == kSliderKVOContext) {
        if(!self.ignore){
            self.slider.value = [change[NSKeyValueChangeNewKey] doubleValue];
        }
    } else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}