adding something to a setter

  • The property syntax is great until you need one more thing.

    Think of a NSView and that view displays a value.

    @synthesize value;

    Now you also want to setNeedsDisplay: when a new value is set. So one
    can override the setter.

    - (void)setValue:(NSString*)theValue
    {
      ...
      [self setNeedsDisplay:YES];
    }

    but - you would have to implement the setter yourself. No big deal -
    but... it sucks.
    Is there a way to forward the setting to the originally synthesized
    setter? Super cannot be it.

    Of course one could add another selector that to the interface

      - (void) setValueAndUpdateDisplay:(NSString*)theValue
      {
        self.value = theValue;
      [self setNeedsDisplay:YES];
      }

    ...but that sucks, too.

    There gotta be a better way!
    How do you deal with this?

    cheers,
    Torsten
  • I don't know of any better way than simply writing the setters yourself.  One thing I'd love to see apple add to the language is allowing us to specify a code block to be included in setter and getting in the synthesize:

    @property (readwrite, retain, nonatomic) NSString *theValue;

    @synthesize (setCode={ [self setNeedsDisplay:YES]; }, getCode={ NSLog(@"It's being set"); });

    would be lovely if it desugared to this in the implementation:

    {
        NSString *theValue;
    }

    - (NSString *)theValue
    {
        { NSLog(@"It's being set"); }
        return [[theValue retain] autorelease];
    }

    - (void)setTheValue:(NSString *)newTheValue
    {
        if (theValue != newTheValue)
        {
            [theValue release];
            theValue = [newTheValue retain];
            { [self setNeedsDisplay:YES]; }
        }
    }

    Does anyone have any comments on why that might not work, before I file a bug report to request it?

    Bob

    if (*ra4 != 0xffc78948) { return false; }

    On 6 Oct 2011, at 12:28, Torsten Curdt wrote:

    > The property syntax is great until you need one more thing.
    >
    > Think of a NSView and that view displays a value.
    >
    > @synthesize value;
    >
    > Now you also want to setNeedsDisplay: when a new value is set. So one
    > can override the setter.
    >
    > - (void)setValue:(NSString*)theValue
    > {
    > ...
    > [self setNeedsDisplay:YES];
    > }
    >
    > but - you would have to implement the setter yourself. No big deal -
    > but... it sucks.
    > Is there a way to forward the setting to the originally synthesized
    > setter? Super cannot be it.
    >
    > Of course one could add another selector that to the interface
    >
    > - (void) setValueAndUpdateDisplay:(NSString*)theValue
    > {
    > self.value = theValue;
    > [self setNeedsDisplay:YES];
    > }
    >
    > ...but that sucks, too.
    >
    > There gotta be a better way!
    > How do you deal with this?
    >
    > cheers,
    > Torsten
  • On 6 Oct 2011, at 13:09, Thomas Davie wrote:

    > I don't know of any better way than simply writing the setters yourself.  One thing I'd love to see apple add to the language is allowing us to specify a code block to be included in setter and getting in the synthesize:
    >
    > @property (readwrite, retain, nonatomic) NSString *theValue;
    >
    > @synthesize (setCode={ [self setNeedsDisplay:YES]; }, getCode={ NSLog(@"It's being set"); });
    >
    > would be lovely if it desugared to this in the implementation:
    >
    > {
    > NSString *theValue;
    > }
    >
    > - (NSString *)theValue
    > {
    > { NSLog(@"It's being set"); }
    > return [[theValue retain] autorelease];
    > }
    >
    > - (void)setTheValue:(NSString *)newTheValue
    > {
    > if (theValue != newTheValue)
    > {
    > [theValue release];
    > theValue = [newTheValue retain];
    > { [self setNeedsDisplay:YES]; }
    > }
    > }
    >
    > Does anyone have any comments on why that might not work, before I file a bug report to request it?

    Well it would become rather unreadable for anything more than a single line of code.
  • I use KVO to execute custom code if a property has changed.

    [self addObserver:self forKeyPath:@"graphics" options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld) context:self];

    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
        if (context != self) {
            [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
        }

        if ([keyPath isEqualToString:@"graphics"]) {
            [self setNeedsDisplay:YES];
        }
    }

    AFAIK the observe method will not be executed instantaneously, but on the other side setNeedsDisplay has also a
    deferred execution.

    Stephan.

    Am 06.10.2011 um 13:28 schrieb Torsten Curdt:

    > The property syntax is great until you need one more thing.
    >
    > Think of a NSView and that view displays a value.
    >
    > @synthesize value;
    >
    > Now you also want to setNeedsDisplay: when a new value is set. So one
    > can override the setter.
    >
    > - (void)setValue:(NSString*)theValue
    > {
    > ...
    > [self setNeedsDisplay:YES];
    > }
    >
    > but - you would have to implement the setter yourself. No big deal -
    > but... it sucks.
    > Is there a way to forward the setting to the originally synthesized
    > setter? Super cannot be it.
    >
    > Of course one could add another selector that to the interface
    >
    > - (void) setValueAndUpdateDisplay:(NSString*)theValue
    > {
    > self.value = theValue;
    > [self setNeedsDisplay:YES];
    > }
    >
    > ...but that sucks, too.
    >
    > There gotta be a better way!
    > How do you deal with this?
  • On 6 Oct 2011, at 13:36, Mike Abdullah wrote:

    >
    > On 6 Oct 2011, at 13:09, Thomas Davie wrote:
    >
    >>
    >> Does anyone have any comments on why that might not work, before I file a bug report to request it?
    >
    > Well it would become rather unreadable for anything more than a single line of code.

    I'm not sure it would be any less readable than code involving blocks tbh.

    What's wrong with:

    @synthesize (
        setCode    {
            [a b];
            [c d:e f:g];
            [h i];
        },
        getCode    {
            ...
        })

    Bob

    if (*ra4 != 0xffc78948) { return false; }
  • Hm... using KVO for an object to observe it's own properties?
    That's feels wrong to me.
    Is that just me?

    cheers,
    Torsten
  • On 6 Oct 2011, at 14:16, Torsten Curdt wrote:

    > Hm... using KVO for an object to observe it's own properties?
    > That's feels wrong to me.
    > Is that just me?

    No, definitely not just you... But then, I find KVO pretty wrong in the first place.

    if (*ra4 != 0xffc78948) { return false; }
  • On Oct 6, 2011, at 6:28 AM, Torsten Curdt wrote:

    > The property syntax is great until you need one more thing.
    >
    > Think of a NSView and that view displays a value.
    >
    > @synthesize value;
    >
    > Now you also want to setNeedsDisplay: when a new value is set. So one
    > can override the setter.
    >
    > - (void)setValue:(NSString*)theValue
    > {
    > ...
    > [self setNeedsDisplay:YES];
    > }
    >
    > but - you would have to implement the setter yourself. No big deal -
    > but... it sucks.
    > Is there a way to forward the setting to the originally synthesized
    > setter? Super cannot be it.
    >
    > Of course one could add another selector that to the interface
    >
    > - (void) setValueAndUpdateDisplay:(NSString*)theValue
    > {
    > self.value = theValue;
    > [self setNeedsDisplay:YES];
    > }
    >
    > ...but that sucks, too.
    >
    > There gotta be a better way!
    > How do you deal with this?

    In your .m file, inside either the class extension or an "internal use only" class category, declare:

    @property (nonatomic, retain) NSString *sideEffectFreeValue;  // or whatever property specifier were on the original property

    and then synthesize it to use the original ivar

    @synthesize sideEffectFreeValue=value;

    and change your setter to:

    - (void) setValue: (NSString *) value
    {
    self.sideEffectFreeValue = value;
    [self setNeedDisplay: YES];
    }

    Glenn Andreas                      <gandreas...>
    The most merciful thing in the world ... is the inability of the human mind to correlate all its contents - HPL
  • But probably that bad feeling is self-inflicted ...

    At least for standard views or controls, if there is a need to redisplay, the property in question should probably belong to a model object not a view object. And in that case your object would not observe its *own* property but a property of the model object - and this observation then would trigger a display refresh. MVC+KVO.

    I hope I am not too wide off the mark.

    Am 06.10.2011 um 15:23 schrieb Thomas Davie:

    >
    > On 6 Oct 2011, at 14:16, Torsten Curdt wrote:
    >
    >> Hm... using KVO for an object to observe it's own properties?
    >> That's feels wrong to me.
    >> Is that just me?
    >
    > No, definitely not just you... But then, I find KVO pretty wrong in the first place.
    >
    > if (*ra4 != 0xffc78948) { return false; }
    >
  • Well, if the model is more complex and you bind the view to the model
    you can of course trigger the re-display on the observed changes. But
    what about a simple title property of e.g. a NSButton?

    ...and I guess triggering a re-display is not the only use case for
    this "setter extension" - or whatever you want to call it.

    cheers,
    Torsten

    On Thu, Oct 6, 2011 at 3:32 PM, Peter <magnard...> wrote:
    > But probably that bad feeling is self-inflicted ...
    >
    > At least for standard views or controls, if there is a need to redisplay, the property in question should probably belong to a model object not a view object. And in that case your object would not observe its *own* property but a property of the model object - and this observation then would trigger a display refresh. MVC+KVO.
    >
    > I hope I am not too wide off the mark.
    >
    > Am 06.10.2011 um 15:23 schrieb Thomas Davie:
    >
    >>
    >> On 6 Oct 2011, at 14:16, Torsten Curdt wrote:
    >>
    >>> Hm... using KVO for an object to observe it's own properties?
    >>> That's feels wrong to me.
    >>> Is that just me?
    >>
    >> No, definitely not just you... But then, I find KVO pretty wrong in the first place.
    >>
    >> if (*ra4 != 0xffc78948) { return false; }
    >>

    >
  • Am 06.10.2011 um 15:54 schrieb Torsten Curdt:

    > Well, if the model is more complex and you bind the view to the model
    > you can of course trigger the re-display on the observed changes. But
    > what about a simple title property of e.g. a NSButton?
    >
    > ...and I guess triggering a re-display is not the only use case for
    > this "setter extension" - or whatever you want to call it.

    I never implement setters/getters for myself. I find it error-prone and it feels wrong to me.

    To give you another example. I use KVO to generate background images
    in UIButton

    [self addObserver:self forKeyPath:@"color" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld | NSKeyValueObservingOptionInitial context:NULL];
    [self addObserver:self forKeyPath:@"size" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld | NSKeyValueObservingOptionInitial context:NULL];
    [self addObserver:self forKeyPath:@"showShadow" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld | NSKeyValueObservingOptionInitial context:NULL];

    - (void)observeValueForKeyPath:(NSString *)keyPath
                          ofObject:(id)object
                            change:(NSDictionary *)change
                          context:(void *)context {
        if (![change keyValueChanged]) {
            return;
        }

        if([keyPath isEqualToString:@"color"] ||
          [keyPath isEqualToString:@"size"] ||
          [keyPath isEqualToString:@"showShadow"]) {
            [self setBackgroundImage:[HDEButton backgroundImageForButtonWithColor:self.color size:self.size] forState:UIControlStateNormal];
            [self setBackgroundImage:[HDEButton backgroundImageForButtonWithColor:HDEGrayBackgroundColor size:self.size] forState:UIControlStateDisabled];
    [...]

    Self observing works great for me.
  • On Oct 6, 2011, at 9:16 AM, Torsten Curdt wrote:
    > Hm... using KVO for an object to observe it's own properties?
    > That's feels wrong to me.
    > Is that just me?

    You could factor the observing out into a separate object.

    I'm just rattling this idea off the top of my head, so it might be flawed (if not outright nuts), but... you could have a class called MyDisplayTickler with a global shared instance. It observes a fake view property called myNeedsDisplay.

    Here is a totally untested MyDisplayTickler class, plus a category on NSView:

    <https://gist.github.com/1267594>

    With these in place, your view class does three trivial things:

    * In its init, it does [[MyDisplayTickler sharedInstance] startObservingView:self].

    * In its dealloc, it does [[MyDisplayTickler sharedInstance] stopObservingView:self].

    * It implements +propertiesThatTriggerDisplay, something like this:

    + (NSArray *)propertiesThatTriggerDisplay
    {
        return [NSArray arrayWithObjects:
                @"titleColor",
                @"fontForHighScore",
                @"selectedShape",  // etc.
                nil];
    }

    What do you all think? I've run into the problem Torsten describes and would like to think there's *some* better solution than writing setters.

    --Andy
  • On 6 Oct 2011, at 15:23, Stephan Michels wrote:

    >
    > Am 06.10.2011 um 15:54 schrieb Torsten Curdt:
    >
    >> Well, if the model is more complex and you bind the view to the model
    >> you can of course trigger the re-display on the observed changes. But
    >> what about a simple title property of e.g. a NSButton?
    >>
    >> ...and I guess triggering a re-display is not the only use case for
    >> this "setter extension" - or whatever you want to call it.
    >
    > I never implement setters/getters for myself. I find it error-prone and it feels wrong to me.
    >
    > To give you another example. I use KVO to generate background images
    > in UIButton
    >
    > [self addObserver:self forKeyPath:@"color" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld | NSKeyValueObservingOptionInitial context:NULL];
    > [self addObserver:self forKeyPath:@"size" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld | NSKeyValueObservingOptionInitial context:NULL];
    > [self addObserver:self forKeyPath:@"showShadow" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld | NSKeyValueObservingOptionInitial context:NULL];
    >
    > - (void)observeValueForKeyPath:(NSString *)keyPath
    > ofObject:(id)object
    > change:(NSDictionary *)change
    > context:(void *)context {
    > if (![change keyValueChanged]) {
    > return;
    > }
    >
    > if([keyPath isEqualToString:@"color"] ||
    > [keyPath isEqualToString:@"size"] ||
    > [keyPath isEqualToString:@"showShadow"]) {
    > [self setBackgroundImage:[HDEButton backgroundImageForButtonWithColor:self.color size:self.size] forState:UIControlStateNormal];
    > [self setBackgroundImage:[HDEButton backgroundImageForButtonWithColor:HDEGrayBackgroundColor size:self.size] forState:UIControlStateDisabled];
    > [...]
    >
    > Self observing works great for me.

    Note that you should really pass in a context pointer and test that in the -observe… method, rather than testing the key paths. Call super for all other key paths.
  • On Oct 6, 2011, at 10:55 AM, Andy Lee wrote:
    > It observes a fake view property called myNeedsDisplay.
    >
    > Here is a totally untested MyDisplayTickler class, plus a category on NSView:
    >
    > <https://gist.github.com/1267594>

    Oops, in my code I called the fake property "needsTickle", not "myNeedsDisplay". It compiles, but again I haven't tested it.

    --Andy
  • On Oct 6, 2011, at 10:57 AM, Mike Abdullah wrote:
    > Note that you should really pass in a context pointer and test that in the -observe… method, rather than testing the key paths. Call super for all other key paths.

    Ah, right. I've updated my gist accordingly.

    --Andy
  • It's perhaps helpful to remember that property was introduce to remove the
    annoyance with having to define boilerplate accessor for 90% of your
    properties. People are now writing 90% less accessor code, so writing one
    more for your case below seems tolerable. After all, it's just a few lines
    of code.

    Yi

    On Thu, Oct 6, 2011 at 4:28 AM, Torsten Curdt <tcurdt...> wrote:

    > The property syntax is great until you need one more thing.
    >
    > Think of a NSView and that view displays a value.
    >
    > @synthesize value;
    >
    > Now you also want to setNeedsDisplay: when a new value is set. So one
    > can override the setter.
    >
    > - (void)setValue:(NSString*)theValue
    > {
    > ...
    > [self setNeedsDisplay:YES];
    > }
    >
    > but - you would have to implement the setter yourself. No big deal -
    > but... it sucks.
    > Is there a way to forward the setting to the originally synthesized
    > setter? Super cannot be it.
    >
    > Of course one could add another selector that to the interface
    >
    > - (void) setValueAndUpdateDisplay:(NSString*)theValue
    > {
    > self.value = theValue;
    > [self setNeedsDisplay:YES];
    > }
    >
    > ...but that sucks, too.
    >
    > There gotta be a better way!
    > How do you deal with this?
    >
    > cheers,
    > Torsten
    >
  • On Oct 6, 2011, at 04:28 , Torsten Curdt wrote:

    > Now you also want to setNeedsDisplay: when a new value is set. So one
    > can override the setter.
    >
    > - (void)setValue:(NSString*)theValue
    > {
    > ...
    > [self setNeedsDisplay:YES];
    > }
    >
    > but - you would have to implement the setter yourself. No big deal -
    > but... it sucks.

    I think it really doesn't suck. You've just been lucky enough so far to be able to ride around on synthesized setters, so an override feels bad. Get over it already!

    The only part of a setter override that perhaps hurts (other than having to type a few extra keystrokes) is that you lose access to the lightweight implementation of the "atomic" attribute. It's easy to obsess about that too, but the class of thread synchronization problems that atomicity actually solves, compared to the class of synchronization problems that need a higher-level strategy, is so small that it's not worth avoiding setters only for this reason.

    By all means use self-observation if that solves your problem. There's absolutely nothing wrong with it, so any negative feelings you might have are just another perceptual problem. Note, however, that because the observer mechanism is so clunky, you're going to write *more* lines of code this way than in overriding the setter, yet all it buys you is the unwanted/unnecessary "atomic" implementation.

    FWIW.
  • On Thu, Oct 6, 2011 at 12:33 PM, Quincey Morris
    <quinceymorris...> wrote:
    > By all means use self-observation if that solves your problem. There's absolutely nothing wrong with it, so any negative feelings you might have are just another perceptual problem. Note, however, that because the observer mechanism is so clunky, you're going to write *more* lines of code this way than in overriding the setter, yet all it buys you is the unwanted/unnecessary "atomic" implementation.

    Not necessarily. If you expect subclasses to add properties that
    require poking -setNeedsDisplay:, or you just have a lot of them, it's
    probably worth adding a class method like +keyPathsRequiringRedisplay,
    register as self-observers for all these keypaths, and provide a
    really simple implementation of -observeValueForKeyPath:… that calls
    [self setNeedsDisplay].

    As far as "unwanted/unnecessary 'atomic'" is concerned, don't get me
    started. That design mistake is going to haunt us forever.

    --Kyle Sluder
  • On Oct 6, 2011, at 4:12 PM, Kyle Sluder wrote:
    > On Thu, Oct 6, 2011 at 12:33 PM, Quincey Morris
    > <quinceymorris...> wrote:
    [...]
    >> Note, however, that because the observer mechanism is so clunky, you're going to write *more* lines of code this way than in overriding the setter, yet all it buys you is the unwanted/unnecessary "atomic" implementation.
    >
    > Not necessarily. If you expect subclasses to add properties that
    > require poking -setNeedsDisplay:, or you just have a lot of them, it's
    > probably worth adding a class method like +keyPathsRequiringRedisplay,
    > register as self-observers for all these keypaths, and provide a
    > really simple implementation of -observeValueForKeyPath:… that calls
    > [self setNeedsDisplay].

    This is what the code I dashed off this morning does (or at least intends to do), except it puts the clunky KVO code into a separate convenience class that you can drop into any project.

    I just now cleaned up some silly mistakes and stole Kyle's "keyPathsRequiringRedisplay" name, though it still isn't perfect (see the description) and totally untested.

    <https://gist.github.com/1267594>

    --Andy
  • > I think it really doesn't suck. You've just been lucky enough so far to be
    > able to ride around on synthesized setters, so an override feels bad. Get
    > over it already!

    Just because I can now synthesize setters doesn't make it suck less.
    Over it or under it ;)

    The intend of this mail was not to bitch though, instead to see if
    there was something I have missed. Looks like I didn't...

    > The only part of a setter override that perhaps hurts (other than having to
    > type a few extra keystrokes) is that you lose access to the lightweight
    > implementation of the "atomic" attribute. It's easy to obsess about that
    > too, but the class of thread synchronization problems that atomicity
    > actually solves, compared to the class of synchronization problems that need
    > a higher-level strategy, is so small that it's not worth avoiding setters
    > only for this reason.

    While I agree that this is not a big deal in practice, I am sure you'd
    agree that it would be indeed nice if we could somehow call out to the
    synthesized setters. I don't have so deep insights into the Obj-C
    runtime but I was wondering if there is some magic one can pull off to
    get to the original setters.

    cheers,
    Torsten
  • On Oct 6, 2011, at 5:34 PM, Torsten Curdt wrote:

    > While I agree that this is not a big deal in practice, I am sure you'd
    > agree that it would be indeed nice if we could somehow call out to the
    > synthesized setters. I don't have so deep insights into the Obj-C
    > runtime but I was wondering if there is some magic one can pull off to
    > get to the original setters.

    You could probably do that via method swizzling, but either using a private property or using KVO would probably be a lot less clunky.

    Charles
  • On Oct 6, 2011, at 15:34 , Torsten Curdt wrote:

    > While I agree that this is not a big deal in practice, I am sure you'd
    > agree that it would be indeed nice if we could somehow call out to the
    > synthesized setters. I don't have so deep insights into the Obj-C
    > runtime but I was wondering if there is some magic one can pull off to
    > get to the original setters.

    In fact, I was just about to post on this.

    As an alternative to the observer approach, it certainly is possible to switch a method of your own choosing in to replace the synthesized setter. Getting the coding-time usability right seems like the main issue.

    It occurs to me that there may be a lower-tech solution. If you created an abstract superclass of the class whose setters you wanted to override, you could synthesize the properties in the superclass, override them normally, and call super in the subclass. There's still a bit of ugliness in this approach (e.g. you have to expose the private superclass in the subclass's public .h file), though not much perhaps. Also, since the compilers have been getting pickier in their recent versions regarding the way property methods are defined, there may turn out to be a compile-time obstacle, but in principle I think this approach should work -- you'd basically be getting the compiler to delve into the runtime for you.

    Again, though, I remain unconvinced that going to all this trouble is worth it, just to eliminate a lingering sense of unease. Perhaps a short course of therapy instead?

    Regarding the observer approach…

    I have no great technical, moral or psychological objections to this approach, but a couple of small things still worry me:

    -- The source code for a simple custom setter is kind of … obvious … to read. It's an instantly recognizable pattern. I've always found observations somewhat difficult to come back to and understand, after the code has already been written, perhaps because the 'observe…' method exists at some random, disconnected place, and decoding the execution flow through it can be mind-bending in all but the simplest cases. Quite often this approach leads to nested observations, with the add/remove observers needing to get done inside an 'observe…' method also. OTOH, maybe a short course of therapy would cure me of the feeling.

    -- Adding an observer creates a not-insignificant amount of internal machinery per observed object. For observing a few views, this isn't significant in practice. As a design principle for a generally useful mechanism, the prospect of unwittingly creating observations for maybe hundreds of thousands of objects seems like a drawback.

    -- There's an actual semantic difference between the two approaches. If you write custom setters in a class hierarchy, you get to control on a class-by-class basis whether the behavior added at one level (such as the 'setNeedsDisplay:') is also inherited. If you add an observer, even an explicit custom setter override at a lower level (for example, one that wants to do 'setNeedsDisplayInRect:' instead) can't turn off the observer behavior.

    In other words, encapsulation is violated. That's fine if that's what you want, but it isn't really a drop-in replacement for the semantics of custom setters.
  • The superclass approach is sneaky ...didn't think about that.

    > Again, though, I remain unconvinced that going to all this trouble is worth
    > it, just to eliminate a lingering sense of unease. Perhaps a short course of
    > therapy instead?

    LOL - maybe :)

    Well, TBH this is less of "I want to use this" but more a "is it possible".
    It's the curious child in me that wants to know :)

    <snip/>

    > In other words, encapsulation is violated. That's fine if that's what you
    > want, but it isn't really a drop-in replacement for the semantics of custom
    > setters.

    That's actually a good point.

    cheers,
    Torsten
  • On Oct 6, 2011, at 6:22 PM, Quincey Morris wrote:

    > It occurs to me that there may be a lower-tech solution. If you created an abstract superclass of the class whose setters you wanted to override, you could synthesize the properties in the superclass, override them normally, and call super in the subclass. There's still a bit of ugliness in this approach (e.g. you have to expose the private superclass in the subclass's public .h file), though not much perhaps. Also, since the compilers have been getting pickier in their recent versions regarding the way property methods are defined, there may turn out to be a compile-time obstacle, but in principle I think this approach should work -- you'd basically be getting the compiler to delve into the runtime for you.

    But isn't creating a whole abstract superclass for this a lot more of a hassle than just making a private property? What would you get from that approach that you wouldn’t get from just having the getters and setters for a property “foo” call through to the synthesized accessors for a private property “privateFoo”?

    Charles
  • On Oct 6, 2011, at 17:12 , Charles Srstka wrote:

    > But isn't creating a whole abstract superclass for this a lot more of a hassle than just making a private property?

    *Some* more. I'm not sure about a *lot* more.

    > What would you get from that approach that you wouldn’t get from just having the getters and setters for a property “foo” call through to the synthesized accessors for a private property “privateFoo”?

    Functionally, they're pretty similar, I guess -- one property uses another in both cases.

    The only real experience I have with a dual-property approach is via Core Data (foo vs primitiveFoo -- imagine we're trying to put a 'setNeedsDisplay:' in a Core Data property override, so that we need to call through to primitiveFoo). It seems straightforward enough conceptually, but when you try to use it, things get hard.

    Now if you find other functionality to add to the property, you have to ask yourself whether you're modifying the primitive property or the public property. Often, the answer is "Duh, I dunno." KVO can get tricky, because the notifications start to go round in circles or just break, and it's not clear how to fix the problem. You start having to guess how having two more or less identical properties interact with (say) undo. If you start subclassing, you again may have puzzling decisions about how and where to add overriding behavior.

    I don't say it can't be done. I'm just saying when I've tried it for real I've found myself in a classic Houdini bind (that is, handcuffed, chained and locked in a steamer trunk at the bottom of a river) without actual Houdini skills to get me out.

    But maybe that's just me.
  • Do not use self as your observation context.

    Your observation context has to be unique for all observers of the object.  “self” is a bad choice.

    Also, you should only do your own work in the case that the observer is your observer. In the code below, you are also doing your work in the case where you should only be calling through to super.

    —Jim

    On Oct 6, 2011, at 5:47 AM, Stephan Michels wrote:

    > I use KVO to execute custom code if a property has changed.
    >
    > [self addObserver:self forKeyPath:@"graphics" options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld) context:self];
    >
    > - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    > if (context != self) {
    > [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    > }
    >
    > if ([keyPath isEqualToString:@"graphics"]) {
    > [self setNeedsDisplay:YES];
    > }
    > }
    >
    > AFAIK the observe method will not be executed instantaneously, but on the other side setNeedsDisplay has also a
    > deferred execution.
    >
    > Stephan.
  • On Thu, 06 Oct 2011 13:28:43 +0200, Torsten Curdt <tcurdt...> said:
    > The property syntax is great until you need one more thing.
    >
    > Think of a NSView and that view displays a value.
    >
    > @synthesize value;
    >
    > Now you also want to setNeedsDisplay: when a new value is set.

    Isn't this the same as the discussion we had here?

    <http://www.cocoabuilder.com/archive/cocoa/304465-synthesised-properties-and
    -additional-actions.html
    >

    If so, let's pretend I just repeat my answer. :) m.

    --
    matt neuburg, phd = <matt...>, <http://www.apeth.net/matt/>
    A fool + a tool + an autorelease pool = cool!
    Programming iOS 4!
    > Isn't this the same as the discussion we had here?
    >
    > <http://www.cocoabuilder.com/archive/cocoa/304465-synthesised-properties-and
    -additional-actions.html
    >
    >
    > If so, let's pretend I just repeat my answer. :) m.

    Wow - a black cat! (http://www.imdb.com/title/tt0133093/quotes)

    Somehow I didn't see it in June. Sorry about that.

    cheers,
    Torsten
previous month october 2011 next month
MTWTFSS
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            
Go to today