Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set value without trigger KVO

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];
like image 483
Leo Zhang Avatar asked Jan 27 '13 00:01

Leo Zhang


2 Answers

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.

like image 141
Tommy Avatar answered Sep 24 '22 06:09

Tommy


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:.

like image 30
Fruity Geek Avatar answered Sep 21 '22 06:09

Fruity Geek