Can I override setValue: forKey:?
key-value-coding, objective-c
Solution
There are definitely ways to do this. You could declare the relevant properties `@dynamic` and then use `+resolveInstanceMethod:` to actually create the setter on-demand. You can find an example like this in the sample code for iOS:PTL. This example demonstrates how to automatically make your accessors read and write to a dictionary (`properties`) rather than from ivars. To make this work for you, you'd probably need to always store `NSNull` in the dictionary and override the getter (`propertyIMP()`) to convert it to `nil`. So you'd change this:
[[self properties] setValue:value forKey:key];
to:
[[self properties] setValue:(value ?: [NSNull null]) forKey:key];
And change:
return [[self properties] valueForKey:NSStringFromSelector(_cmd)];
to:
id value = [[self properties] valueForKey:NSStringFromSelector(_cmd)];
return (value == [NSNull null] ? nil : value);
Or something like that.
BUT... unless this is a major win, I would avoid this kind of magic. My typical solution to this is to go the other way, and put it on the caller not to pass `[NSNull null]` when they shouldn't. I use a function like `RNNonNull()`:
id RNNonNull(id x) { return (x == [NSNull null]) ? nil : x; }
Then the caller is responsible for adding the wrapper:
obj.foo = RNNonNull(mystuff);
If that's not possible, I'd probably override the getters by hand to convert `NSNull` to `nil` rather than doing it with the runtime (it'd be a one-line method). The only reason I'd use the runtime is if there were a bunch of properties, and the object were very simple (purely a data object).
Problem
I have an object that is likely to have NSNull set as a value on all of its properties, and I'm working with code that doesn't play nice with NSNull values. Is it possible to override setValue: forKey: in my object like this? ``` -(void)setValue:(id)value forKey:(NSString *)key { if ([value isEqual:[NSNull null]]) { [super setValue:nil forKey:key]; } else { [super setValue:value forKey:key]; } } ``` The method doesn't get called when `object.property = [NSNull null]` gets set on it. How can I make this the default behavior for my setters?