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