Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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!

like image 570
Sergio Moura Avatar asked Feb 04 '26 08:02

Sergio Moura


2 Answers

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

like image 77
paulmelnikow Avatar answered Feb 06 '26 00:02

paulmelnikow


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

like image 39
aleroot Avatar answered Feb 06 '26 00:02

aleroot