How to set value without trigger KVO
Asked Answered
S

3

5

I use the following code to add KVO on object.

[self.model addObserver:self
             forKeyPath:@"userName"
                options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
                context:nil];

Now I want to set the userName like below. Yes, it will trigger KVO.

self.model.userName = @"testUser";

However, I want to set value without trigger KVO. How to do that? Are there any method like below allowing me to do that?

[self.model setValue:@"testUser" forKey:@"userName" isSilent:YES];
Seductive answered 27/1, 2013 at 0:45 Comment(1)
Can you explain more about what you're trying to do? Why do you want to sometimes not trigger KVO?Pandora
C
6

Your design is broken if you want to do this. The point of key-value observing is that someone wants to know when a field changes so they register for notifications. The point of being key-value observing compliant is that you're keeping your options open as to how the rest of the system interacts with you.

What it sounds like you're doing is trying to hack around some problem where you don't want someone to know the true value of a property for some reason. So they think they're getting updates but actually if they were to check the property then it'd turn out you were deliberately lying.

As you'd expect, Cocoa doesn't have any mechanisms to support such hacks. They're extremely bad practice, breaking the whole structure of object-oriented programming.

Lecturing aside, you could write a custom setter that went directly to the instance variable. So, e.g.

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

At the system level, key-value observing is implemented by creating a new version of the property setter that contains a call to the real setter and makes appropriate observer calls around the outside. So avoiding the real setter would avoid the notifications.

Cheroot answered 27/1, 2013 at 0:55 Comment(1)
If I were guessing about the PO's intent, I'd guess that he's trying to detect some higher level state change that he might have conflated with a single key. If that were so, good advice would be to understand the state change explicitly and use NSNotificationCenter or something else. Maybe the better thing to do is to just ask the PO about his intent.Pandora
G
6

Core Data implements setPrimitiveValue:forKey: to allow you to do this. You can implement the same method in your object.

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

When doing this however, it should be in the context of aggregating notifications where the observer is eventually notified with manual willChangeValueForKey: and didChangeValueForKey:.

Gilleod answered 27/1, 2013 at 1:24 Comment(0)
C
0

You can use an ignore flag. Same idea as changeIsUserDriven in the docs under 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];
    }
}
Crackerbarrel answered 29/10, 2020 at 19:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.