0

I am writing a programme for Mac OS X, and came across the following problem:

In one of my classes there is a number of boolean properties, which are accessed using KVO (that is, by valueForKey: and setValue:forKey: methods. Their number is likely to grow.

Each time i set one of these properties, i need to change the date of the last modification, which is also a property. So i end up having to write a new setter for each new property.

What i would like to do instead is to override the setValue:forKey: method so that it set the corresponding property and the date of the last modification, but i can't figure out how to do that without a) adding ifs to the setValue:forKey: method (to check the name of the key and set the corresponding _variable); and b) without falling into an infinite cycle.

Is there a way to do it? Or is it a bad idea altogether?

Ibolit
  • 9,218
  • 7
  • 52
  • 96
  • Do you need to check the key? Can you just call `super` and use `_data` to update the mod date? – Wain Sep 14 '13 at 18:26
  • @Wain do you mean, calling [super setValue:... forKey:...]? Not sure it will work, but I can try. – Ibolit Sep 14 '13 at 18:39
  • 1
    Why don't you just implement the setter? – Ramy Al Zuhouri Sep 14 '13 at 18:52
  • I have :). I was just thinking if it is possible to do without it. It would leave less room for error when i add another of those boolean properties in future. I want to be able just to add the "@property"... and leave it at that. – Ibolit Sep 14 '13 at 19:21

1 Answers1

2

Both issues a) and b) can be solved by simply calling the implementation of the NSObject superclass in your overridden implementation:

- (void)setValue:(id)value forKey:(NSString *)key
{
    _lastModificationDate = [NSDate date];
    [super setValue:value forKey:key];
}

There will be no infinite cycle because calling the super class will not result in any kind of recursion. Also, there is no need to call your setters or set your instance variables explicitly because the super class implementation will take care of this.

hverlind
  • 500
  • 1
  • 7
  • 14
  • 1
    Note that in general, however, overriding `setValue:forKey:` is a bad idea. It will only work as expected when you are calling `setValue:forKey` explicitly to set your property values (as mentioned in the question). When you call `setValue:forKey`, the property setters will be triggered, but the opposite is *not* true. If anyone calls a property setter directly, `setValue:forKey` will not be called and the modification date will not be updated. A better (but less elegant) solution would be to let the object observe its own relevant properties and set the date in `observeValueForKeyPath`. – hverlind Sep 15 '13 at 09:47
  • Is it possible to "hide" the setters somehow? For example, if i declare the property "readonly" or if I declare it in the interface extension in the implementation file, will setValue:forKey: still work? (Sorry, I know it is easy to check myself, but I am not at my mac now) – Ibolit Sep 17 '13 at 08:10
  • Yes, `setValue:forKey` will still "work" if you declare your properties readonly (accessing the instance variable directly if there is no setter for the property), but it's not exactly a nice design. – hverlind Sep 17 '13 at 18:27