What is Key-Value-Coding and Key-Value-Observing in Objective C? - objective-c

Can someone explain in simple terms what is Key-Value-Coding and Key-Value-Observing? Please don't provide links to Apple Developer's reference Document. I have gone through them. I expect an explanation in very simple terms.

Key-Value-Coding (KVC) means accessing a property or value using a string.
id someValue = [myObject valueForKeyPath:#"foo.bar.baz"];
Which could be the same as:
id someValue = [[[myObject foo] bar] baz];
Key-Value-Observing (KVO) allows you to observe changes to a property or value.
To observe a property using KVO you would identify to property with a string; i.e., using KVC. Therefore, the observable object must be KVC compliant.
[myObject addObserver:self forKeyPath:#"foo.bar.baz" options:0 context:NULL];

Key Value Coding is simply accessing a property of an object through a string instead of the literal syntax.
// Here is a new instance of an object
Foo *foo = [[Foo alloc] init];
// Accessing a property called someValue with literal syntax:
[foo someValue];
// Accessing the same property with dot notation
foo.someValue;
// Accessing the same property with Key-Value coding:
[foo valueForKey:#"someValue"];
The power of KVC is that you can specify any arbitrary string at runtime (obviously this could be very dangerous too).

Key-value coding allows you to fetch or change a property of an object using a string, at runtime, instead of needing to write code that is compiled to a fixed property from the start:
NSNumber* foo = [myPopup valueForKey: #"selectedItemIndex"];
[myPopup setValue: #15 forKey: #"selectedItemIndex"];
A good example for this is NSTableView on Mac, where you can just set an identifier on every table column that corresponds to your model object's property that it should display, and then your data source just calls -valueForKey:/-setValue:forKey: with the column's identifier as the key and the values pretty much display/set themselves. You just add the right columns to the table view in the XIB.
Key-value observing was added afterwards, and lets you register to be notified about changes made to another object. You register your interest by doing:
void* gMyKVOContext = &gMyKVOContext; // global variable somewhere that guarantees us a unique address that doesn't collide with a subclass's registration for observing the same property
...
[interestingObject addObserver: interestedObject forKeyPath: #"interestingProperty" options: 0 context: gMyKVOContext];
Whenever that property is changed, -observeValueForKeyPath:ofObject:change:context: will be called on the object you specified as the observer. So you'd implement that like:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if( context == gMyKVOContext && [keyPath isEqualToString: #"interestingProperty"] )
{
// Update UI that shows interestingProperty
}
else
[super observeValueForKeyPath: keyPath ofObject: object change: change context: context];
}
The advantage here is that you get called live the moment that other property is changed. Note that objects have to do a little work so these notifications are sent, so not all properties are key-value-observable. Also note that some objects may be in an invalid state if two related properties get changed right after the other: You get notified after the first property has been changed, which now contradicts the second, and only then the second property is changed and you're notified for that. So during that first observer callback, the object may be in a weird state, so be careful how you react to that.
To make a property observable, either use the default #synthesized implementation when you define it, or if you define it yourself, implement the setter like:
-(void) setFoo: (int)inFoo
{
[self willChangeValueForKey: #"foo"];
_foo = inFoo;
[self didChangeValueForKey: #"foo"];
}
Then always go through the setter to change it, don't change _foo directly. If you have related properties that could contradict each other like the above, a good way to avoid this is to always change them both in pairs (you can't use KVC then, though). To do that, implement a combined setter like:
-(void) setFoo: (int)inFoo bar: (int)inBar
{
[self willChangeValueForKey: #"foo"];
[self willChangeValueForKey: #"bar"];
_foo = inFoo;
_bar = inBar;
[self didChangeValueForKey: #"bar"];
[self didChangeValueForKey: #"foo"];
}
That way, both notifications are sent while the properties are in proper states.

Start here.
Key-value coding is a mechanism for
accessing an object’s properties
indirectly, using strings to identify
properties, rather than through
invocation of an accessor method or
accessing them directly through
instance variables.

Objective-C Key Value Coding(KVC) vs Key Value Observing(KVO)
[Swift KVC]
KVC allows you to access to property by String it is enabled for all NSObject successors. It adds a dynamism in the language. You can consider your class as Dictionary(Key-Value). It is an alternative/not direct solution to assign/read/write variables
[valueForKey vs valueForKeyPath]
B *b = [a valueForKeyPath:#"b"];
KVC is used by KVO, as well as CoreData, Cocoa bindings...
KVO allows you to subscribe on value changed. It is working for dynamic dispatch
someClass.observe(\.v, options: .new) { (object, change) in
//logic
}
[KVO example]

Related

Call a method every time a parameter is set on Objective-C (Cocoa)

I currently have a class with 15 properties (and growing), and I'm finding myself having to call an update method every time one of those properties change.
Currently, I'm overriding every setter with a code like this:
-(void)setParameterName:(NSUInteger)newValue {
if (_param == newValue)
return;
_param = newValue;
[self redraw];
}
The method [self redraw]; being the key here.
Is there a better way to do it? Should I be using keyValue observers (the method observeValue:forKeyPath:ofObject:change:context:)?
Notes:
All properties (so far) are assign (mostly enum, NSUInteger, CGFloat and BOOL);
All those properties are set using bindings (method bind:toObject:withKeyPath:options:). Except when loading from the filesystem (which is not important, as I already call the drawing methods on every object after the loading is done);
The value changes are only for the current object. I do not need to be told when changes occur on other objects;
I have other properties that I don't need to watch the changes on it (because it will have no effect on my output and drawing the output is kinda time-consuming).
Thanks!
Since these properties are updated using bindings, which invoke -setValue:forKey:, you can override that method instead of writing custom setters:
+ (NSArray *) keysAffectingDrawing {
static NSArray *singleton;
if (!singleton)
singleton = [NSArray arrayWithObjects:
#"property1",
#"property2",
#"property3",
nil];
return singleton;
}
- (void) setValue:(id) value forKey:(NSString *) key {
[super setValue:value forKey:key];
if ([[CustomClass keysAffectingDrawing] containsObject:key]) [self redraw];
}
(I was first inclined recommend key-value observing but agree it's not the best solution here. I think the reason is in part that there's only one object, and in part because the design doesn't follow MVC. Usually in MVC an object that draws itself isn't the one with all the properties.)
(Added: Ahh, I see. The model is responsible for rendering the properties to a bitmap, and that's what -redraw does. That's fine MVC. To make it clearer, I recommend changing the name of the method from -redraw to something like -updateImage or -renderImage, since it doesn't actually do any drawing.)
You could use the Key-Value Observing to avoid repeating in all properties setter the method call, however i think that calling the method directly in the setter is not the wrong way to do it, and could even be faster ...

NSMutableDictionary KVO

I'm trying to observe changes in dictionary using KVO.
Example:
dictionary = [NSMutableDictionary new];
[dictionary setObject:#"test1" forKey:#"key1"];
[dictionary setObject:#"test2" forKey:#"key2"];
[dictionary setObject:#"test3" forKey:#"key1"];
I'd love to be able to hook an observer for whenever a value is added to the dictionary. removed, or replaced (ie in the above cases, whenever any of the setObject methods are called)
So in conclusion:
I want a function to have
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
called when I ADD a any new entry to a dictionary, or Remove any entry, or REPLACE any entry.
NOT: I do NOT want to have to specify which keys I'm observing for. (eg observe only when #"key1" is added) as this solution doesn't scale.
Subclassing NSMutableDictionary is a bit annoying, due to the fact that NSDictionary and its friends are class clusters. It's certainly doable, and if you have to pass the object itself to another set of classes, then you may want to do exactly that. Otherwise, it might be easier to create a composite class which has the same basic API and uses NSMutableDictionary object internally for storage. There's a pretty good write-up as CocoaWithLove.com, Ordered Dictionary Subclassing, which goes into doing this.
However, that doesn't completely solve your problem. What I would suggest is that you begin with a subclass or decorator class such as the one above, then add support explicitly for -(NSArray*)allKeys, which is a standard accessor in NSDictionary itself. Then, you can add support to pass along change messages for allKeys, which will make it observable.
This can be done by adding the following code around the -setObject:forKey: and -removeObjectForKey: methods.
- (void)setObject:(id)anObject forKey:(id)aKey
{
BOOL addKey=NO;
if (![dictionary objectForKey: aKey]) {
addKey=YES;
[self willChangeValueForKey: #"allKeys"];
}
[dictionary setObject:anObject forKey:aKey];
if (addKey)
[self didChangeValueForKey: #"allKeys"];
}
- (void)removeObjectForKey:(id)aKey
{
[self willChangeValueForKey: #"allKeys"];
[dictionary removeObjectForKey:aKey];
[self didChangeValueForKey: #"allKeys"];
}
What is being done here is that we're adding explicit KVO notification to the class when the dictionary's keys are changed to mark a change in the array.
This will take care of adds and removes. If you want changes to be notified on the same basis, you can remove the if statements, and just have allKeys notify on either set or remove, like this:
- (void)setObject:(id)anObject forKey:(id)aKey
{
[self willChangeValueForKey: #"allKeys"];
[dictionary setObject:anObject forKey:aKey];
[self didChangeValueForKey: #"allKeys"];
}
Then, in your code, you put in a single observer for the key #"allKeys" on this object and you'll be receiving notifications whenever an item changes.
I solved a similar problem by adding an observer to the mutable dictionary "translator" in this way:
[self addObserver:self forKeyPath:#"translator.#count" options:0 context:NULL];
My app manages the data in a the classical way, using a tableview, a controller and the dictionary as KVO property "translator".
The dictionary is bound to a NSDictionaryController in my XIB, and a tableview content is bound to the controller.
This are the connections of the tableview:
Now, in any of the following cases I catch the change :
adding a key-value pair
removing a key-value pair
changing a key
changing a value
Remark: unfortunately, this approach does not work with NSMutableArrays.
Changes are not recognized
Can't you subclass NSMutableDictionary and override the various setters? For instance, overriding setObject:forKey: by calling super, then immediately calling addObserver...
You can also write a wrapper for NSMutableDictionary where you force yourself to use custom setters to manipulate the underlying NSMutableDictionary.
Maybe I need more context to any of your limitations or scalability intents.
I hope this will be helpful
- (void)addObserver:(id)observer {
for (id key in grid)
[self addObserver:observer
forKeyPath:[key description]
options:0
context:key];
}
I think another way to do this is using the below override, incase you are observing NSMutableDictionary "allRecentCurrencyData" whose values are dependent on recentBrazilReals, recentEuEuro, recentUkPounds, recentJapanYen, the observer will get called, but the drawback is you need to know the keys before hand to do this.
+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key
{
NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];
if ([key isEqualToString:#"allRecentCurrencyData"]) {
NSArray *affectingKeys = #[#"recentBrazilReals", #"recentEuEuro",#"recentUkPounds",#"recentJapanYen"];
keyPaths = [keyPaths setByAddingObjectsFromArray:affectingKeys];
}
return keyPaths;
}

Objective-C: override dynamic getter

I have an NSManagedObject subclass MyClass with a property myProp, which is defined #dynamic. There are various instances of reading myProp in my code, via [myClass myProp].
Now, I want to define a getter (that returns myProp after appending something to it) for myProp, without changing the various calls to [myClass myProp]. i.e. without creating a getter that is named something other than getMyProp.
My question is, if I create a getter getMyProp, which will override the getter created by NSManagedObject, how do I access the original value that is stored in the database?
To access the underlying values of a managed object you use the following two methods:
- (id)primitiveValueForKey:(NSString *)key
- (void)setPrimitiveValue:(id)value forKey:(NSString *)key
This is often used to convert NSNumber attributes into their 'real' type, for example a bool property:
- (BOOL)isShared
{
[self willAccessValueForKey:#"isShared"];
NSNumber *underlyingValue = [self primitiveValueForKey:#"isShared"];
[self didAccessValueForKey:#"isShared"];
return [underlyingValue boolValue];
}
The willAccessValueForKey: and didAccessValueForKey: are required by the underlying managed object class for handling faults and relationships etc.
And if you do end up writing a setter, you must also wrap the accessor in KVC methods:
- (void)setShared:(BOOL)isShared
{
NSNumber *newUnderlyingValue = [NSNumber numberWithBool:isShared];
[self willChangeValueForKey:#"isShared"];
[self setPrimitiveValue:newUnderlyingValue forKey:#"isShared"];
[self didChangeValueForKey:#"isShared"];
}
Having said this, I would personally not recommend you keep the same method name unless you have a good reason. For 'derived' values you generally want to create a brand new method with a different name. It doesn't take long to do a quick find/replace throughout your code.
EDIT: added willAccessValueForKey:/didAccessValueForKey: (thanks jrturton)

Overwriting Setters for Retain Properties

Is there any way to avoid this kind of code when overwriting the default setter for a retain property?
-(void)setMasterViewController:(UIViewController *)newMaster {
[newMaster retain];
[masterViewController release];
masterViewController = newMaster;
// do custom stuff on set
}
Is there any way to access the default setter, something like:
-(void)setMasterViewController:(UIViewController *)newMaster {
[defaultSetMasterViewController:newMaster];
// do custom stuff
}
This would keep the code DRYer. The way I'm doing it currently, the fact that it's a retain property is mentioned twice.
CoreData generates primitive setters, but in general there's no such affordance. You may be able to replace custom setters with key-value observing in some cases, but the solution to your specific question is probably "use ARC" if you can limit support to 10.6+/4.3+. It will handle the retain/release stuff on your behalf.
Not really, because the setter has to perform the actual setting. You could try doing this using key-value observing if you want to keep the original setter.
However... Yes, if you're using ARC! If you have a #property (strong), then when you simply say masterViewController = newMaster ARC will use objc_storeStrong, which:
Performs the complete sequence for assigning to a __strong object of non-block type. Equivalent to the following code:
id objc_storeStrong(id *object, id value) {
value = [value retain];
id oldValue = *object;
*object = value;
[oldValue release];
return value;
}

Cocoa - Determining a class' properties at run time

Is this simple? I'm actually trying to monitor if an object changes (to determine if I should save it). Currently I just have an array in the object with a list of all of it's readwrite properties, then I loop through it after the object is created and add observers:
for ( NSString *observer in _observers ){
[self addObserver: self forKeyPath: observer options: NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context: nil];
}
It works, but if you forget to add a property to the array, obviously the observer won't be called. Does anyone know how I can just determine the object's properties at runtime? I was thinking it may be around respondsToSelector: but I haven't been able to find much on the subject.
Thanks in advance!
Properties of an object, after they have been synthesized, behave almost like ordinary object's methods, so you can do following check
if ([myObject respondsToSelector: #selector(propertyName)]) {
// your code here
}
Or if you want to use strings as selector's name:
if ([myObject respondsToSelector: NSSelectorFromString(#"propertyName")]) {
// your code here
}
Here propertyName is a getter (it's signature name exactly corresponds to your declared property name), so if you want to check for setter presence, you should add additional expression:
[myObject respondsToSelector: #selector(setPropertyName:)])
May be this will help:
You can get list of properties in a class using class_copyPropertyList
objc_property_t * class_copyPropertyList(Class cls, unsigned int *outCount)
and then from each property you can get its name using property_getName function and attributes using property_getAttributes function (if you need to filter read-write properties).
For more details see Objective-c Runtime Reference