views:

185

answers:

4

Lets say I have a custom control called FooBox. It is just a square on the screen. It has some properties like color, border, etc. When I change the properties, I want the FooBox to redraw itself to reflect its new properties. Is there a way to do that without writing custom setters and putting [self setNeedsDisplay:YES] into all of them?

A: 

Two other ways:

  1. Have whatever is sending the view the accessor message send setNeedsDisplay:YES to it immediately after. Not always possible, and no less of a hassle.
  2. Override setValue:forKey: to add the setNeedsDisplay: message to it, and use that to set the view's properties. This will require boxing up any numeric or structure values, which is trading one hassle for another.

So, effectively, no.

Peter Hosey
A: 

I'm not aware of one. I'd write myself a few macros to do the trick if it bothered me enough.

uliwitness
+1  A: 

EDIT: Peter is right in the comments, this solution only works if there is an observer registered for that property. I remember now that I had done this on a CALayer with @dynamic properties, in which case this works as you would like. In the general case though, this is not a good solution to your problem.

Assuming your class is KVC compliant for the properties which you want to trigger a redisplay, I would override the -didChangeValueForKey: method to call [self setNeedsDisplay] when the key matches one of your properties. I think this is slightly better than Peter's method of overriding -setValue:forKey: because it does not get in the way of the normal KVC machinery and doesn't require the boxing that he mentions.

- (void)didChangeValueForKey:(NSString*)key {
    if ([@"propertyOne" isEqualToString:Key] ||
        ....) {
        [self setNeedsDisplay];
    }
    [super didChangeValueForKey:key]; // <- Don't forget this
}
Jason Foreman
It might be better to use an `NSSet` in this case. Could even make it static if you needed speed
cobbal
That will only get called for any property that something is observing, though, since KVO will only wrap properties that something is observing. Any properties that nothing has started observing will remain unwrapped.
Peter Hosey
cobbal: You mean a set of the properties? I'm not sure it's worth conditionalizing; you could just have the view tell itself it needs display whenever anything sets any of its properties.
Peter Hosey
+3  A: 

I am not certain if this is the right way to do it, but you could consider using NSKeyValueObserving and register the object as observer of itself, and do the redrawing in the -observeValueForKeyPath:ofObject:change:context: method.

Johan Kool