【问题标题】:How to set value without trigger KVO如何在不触发 KVO 的情况下设置值
【发布时间】:2013-01-27 00:45:12
【问题描述】:

我使用以下代码在对象上添加 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];

【问题讨论】:

  • 你能解释一下你想要做什么吗?为什么有时不想触发 KVO?

标签: objective-c key-value-observing


【解决方案1】:

Core Data 实现了setPrimitiveValue:forKey: 以允许您执行此操作。您可以在对象中实现相同的方法。

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

但是,当这样做时,它应该在聚合通知的上下文中,最终通过手动willChangeValueForKey: 和didChangeValueForKey: 通知观察者。

【讨论】:

    【解决方案2】:

    如果你想这样做,你的设计就被破坏了。键值观察的要点是有人想知道字段何时更改,因此他们注册通知。遵守键值观察的关键在于,您可以对系统的其余部分如何与您进行交互保持开放的态度。

    听起来您正在尝试解决一些问题,您不希望有人出于某种原因知道财产的真实价值。所以他们认为他们正在获得更新,但实际上如果他们要检查房产,那么事实证明你是在故意撒谎。

    如您所料,Cocoa 没有任何机制来支持此类黑客攻击。它们是非常糟糕的做法,破坏了面向对象编程的整个结构。

    抛开讲课不谈,您可以编写一个直接访问实例变量的自定义设置器。所以,例如

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

    在系统级别,键值观察是通过创建一个新版本的属性设置器来实现的,该版本包含对真实设置器的调用并在外部进行适当的观察者调用。所以避免真正的 setter 会避免通知。

    【讨论】:

    • 如果我猜测 PO 的意图,我猜他正试图检测一些更高级别的状态变化,他可能已经将其与单个键混为一谈。如果是这样,好的建议是明确理解状态变化并使用 NSNotificationCenter 或其他东西。也许更好的做法是向 PO 询问他的意图。
    【解决方案3】:

    您可以使用忽略标志。与User-Driven Updates 的文档中的想法相同。

    // 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];
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-01
      • 2021-07-03
      • 2011-10-15
      • 2021-05-11
      • 1970-01-01
      • 1970-01-01
      • 2013-05-11
      相关资源
      最近更新 更多