KVO autonotifying complaining about custom setter return value

  • Hi List,

    In attempting to use a custom setter for a object, I'm getting the
    following message in the console the first time that object is
    instantiated:

    KVO autonotifying only supports -set<Key>: methods that return void.
    Autonotifying will not be done for invocations of -[MyObject
    setValue:]

    The setter is returning void and both setter and getter are working as
    expected, so I'm not sure where this is coming from.  My object looks
    like this:

    @interface MyObject : MyObjectSuper
    {
    id value;
    }

    @property (assign, setter=setValueForBindings:) id value;
    -(void) setValueForBindings:(id)_value;

    @end

    @implementation MyObject

    @dynamic value;

    - (id) value
    {
    return( value );
    }

    -(void) setValueForBindings:(id)_value
    {
    [self willChangeValueForKey:@"value"];
    {
      BOOL didSetOK = [self setStringValue:(NSString *)_value];
                    // Do something with didSetOK
    }
    [self didChangeValueForKey:@"value"];
    }
    @end

    > From what I can tell from the documentation, this is all perfectly
    valid.  I even tried removing the method that returns a value inside
    the setter to see if that was the problem and it didn't change
    anything.  Is this a bug or am I just missing something?

    Thanks

    --
    Jim
    http://nukethemfromorbit.com
  • On Tue, Mar 4, 2008 at 11:49 AM, Jim Turner <jturner.lists...> wrote:
    > In attempting to use a custom setter for a object, I'm getting the
    > following message in the console the first time that object is
    > instantiated:
    >
    > KVO autonotifying only supports -set<Key>: methods that return void.
    > Autonotifying will not be done for invocations of -[MyObject
    > setValue:]
    >
    > [snip]
    >
    > -(void) setValueForBindings:(id)_value
    > {
    > [self willChangeValueForKey:@"value"];
    > {
    > BOOL didSetOK = [self setStringValue:(NSString *)_value];
    > // Do something with didSetOK
    > }
    > [self didChangeValueForKey:@"value"];
    > }

    Please re-read the second sentence of that error again.  You are
    manually invoking -willChangeValueForKey: and -didChangeValueForKey:
    and KVO is complaining "I've already done that!".  Either stop doing
    that, or implement -automaticallyNotifiesObserversForKey: to return NO
    for the "bindings" key.

    --Kyle Sluder
  • On 05/03/2008, at 2:10 PM, Kyle Sluder wrote:

    > On Tue, Mar 4, 2008 at 11:49 AM, Jim Turner
    > <jturner.lists...> wrote:
    >> In attempting to use a custom setter for a object, I'm getting the
    >> following message in the console the first time that object is
    >> instantiated:
    >>
    >> KVO autonotifying only supports -set<Key>: methods that return void.
    >> Autonotifying will not be done for invocations of -[MyObject
    >> setValue:]
    >>
    >> [snip]
    >>
    >> -(void) setValueForBindings:(id)_value
    >> {
    >> [self willChangeValueForKey:@"value"];
    >> {
    >> BOOL didSetOK = [self setStringValue:(NSString
    >> *)_value];
    >> // Do something with didSetOK
    >> }
    >> [self didChangeValueForKey:@"value"];
    >> }
    >
    > Please re-read the second sentence of that error again.  You are
    > manually invoking -willChangeValueForKey: and -didChangeValueForKey:
    > and KVO is complaining "I've already done that!".  Either stop doing
    > that, or implement -automaticallyNotifiesObserversForKey: to return NO
    > for the "bindings" key.

    Implementing -automaticallyNotifiesObserversForKey: will solve the
    problem but just removing the calls to -willChangeValueForKey: and -
    didChangeValueForKey: won't.

    I suspect the real cause of the problem is that there's a setValue:
    method defined in the superclass that returns something.

    If you're going to be using KVO/KVC on your objects, you should
    probably reconsider whether it's a good idea for your setter/getter
    methods to use non-default names. Obviously, you can change the name
    of your property if it clashes with methods in your superclass.

    - Chris
  • Chris,

    On Tue, Mar 4, 2008 at 9:47 PM, Chris Suter <chris...> wrote:
    >
    >
    > On 05/03/2008, at 2:10 PM, Kyle Sluder wrote:
    >
    >> On Tue, Mar 4, 2008 at 11:49 AM, Jim Turner
    >> <jturner.lists...> wrote:
    >>> In attempting to use a custom setter for a object, I'm getting the
    >>> following message in the console the first time that object is
    >>> instantiated:
    >>>
    >>> KVO autonotifying only supports -set<Key>: methods that return void.
    >>> Autonotifying will not be done for invocations of -[MyObject
    >>> setValue:]
    >>>
    >>> [snip]
    >>>
    >>> -(void) setValueForBindings:(id)_value
    >>> {
    >>> [self willChangeValueForKey:@"value"];
    >>> {
    >>> BOOL didSetOK = [self setStringValue:(NSString
    >>> *)_value];
    >>> // Do something with didSetOK
    >>> }
    >>> [self didChangeValueForKey:@"value"];
    >>> }
    >>
    >> Please re-read the second sentence of that error again.  You are
    >> manually invoking -willChangeValueForKey: and -didChangeValueForKey:
    >> and KVO is complaining "I've already done that!".  Either stop doing
    >> that, or implement -automaticallyNotifiesObserversForKey: to return NO
    >> for the "bindings" key.

    Actually, these were never getting called at all.  Read below.

    >
    > Implementing -automaticallyNotifiesObserversForKey: will solve the
    > problem but just removing the calls to -willChangeValueForKey: and -
    > didChangeValueForKey: won't.
    >
    > I suspect the real cause of the problem is that there's a setValue:
    > method defined in the superclass that returns something.

    Actually, there was a -(BOOL) setValue: method in the object itself
    that was getting called, I simply didn't see it in there.  KVO/KVC was
    finding it instead of my defined setter method, as it should have.

    Having +automaticallyNotifiesObserversForKey: return NO for "value"
    stopped the warning, but observation stopped as well, regardless if I
    posted will/didChangeValueForKey because my custom setter still wasn't
    getting called (the ivar was getting accessed directly)

    When I implement +accessInstanceVariablesDirectly and have it return
    NO, KVO then complains that my object is now no longer compliant even
    though I have valid values for getter and setter defined in the
    property declaration.  The object responds to my custom methods but is
    missing the connection that the property should be using those as well
    instead of the default.

    I filed a bug (rdar://problems/5781977) as this doesn't appear to be
    proper behavior.  I'd be happy to be told I'm wrong if you can point
    out what I'm missing.

    >
    > If you're going to be using KVO/KVC on your objects, you should
    > probably reconsider whether it's a good idea for your setter/getter
    > methods to use non-default names. Obviously, you can change the name
    > of your property if it clashes with methods in your superclass.
    >
    > - Chris
    >
    >

    Thanks

    --
    Jim
    http://nukethemfromorbit.com
  • On Mar 5, 2008, at 9:34 AM, Jim Turner wrote:

    > I filed a bug (rdar://problems/5781977) as this doesn't appear to be
    > proper behavior.  I'd be happy to be told I'm wrong if you can point
    > out what I'm missing.

    I believe this behaves correctly.
    As stated in <http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/Articl
    es/chapter_5_section_5.html#
    >, "Key-value coding and declared properties are orthogonal
    technologies."
    KVC doesn't know about any custom setter you may have defined for a
    property.

    mmalc
  • On Wed, Mar 5, 2008 at 12:00 PM, mmalc crawford <mmalc_lists...> wrote:
    >
    > On Mar 5, 2008, at 9:34 AM, Jim Turner wrote:
    >
    >> I filed a bug (rdar://problems/5781977) as this doesn't appear to be
    >> proper behavior.  I'd be happy to be told I'm wrong if you can point
    >> out what I'm missing.
    >
    > I believe this behaves correctly.
    > As stated in <http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/Articl
    es/chapter_5_section_5.html#
    >  >, "Key-value coding and declared properties are orthogonal
    > technologies."
    > KVC doesn't know about any custom setter you may have defined for a
    > property.
    >
    > mmalc
    >
    >

    Hmm, it appears the developer documentation I have locally on my
    machine is slightly out of date.  After reading that link (and the
    updated description of setter= and getter=), I see now why what I'm
    doing isn't working.  Properties and KVO/KVC aren't complimentary to
    each other... although it'd be nice if they were.  I'll have to
    re-work my object to get it to be properly compliant.

    But, I still appear to have an issue with defining a custom
    getter/setter.  Defining a property as

    @property (setter=mySetMethod:,getter=myMethod) id valueTest;

    and sending my object a valueTest message, I get the unrecognized
    selector sent to instance warning.  Reading (and re-reading several
    times) http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/Articl
    es/chapter_5_section_3.html#//apple_ref/doc/uid/TP30001163-CH17-SW17

    it appears that I don't need to define anything other than the
    @property but unless I also place

    -(id) valueTest;
    -(void) setValueTest:(id)_value;

    in the interface, the object can't find a method signature.

    This is a little more confusing that I originally thought. I
    appreciate all the help, though.

    --
    Jim
    http://nukethemfromorbit.com
  • On Mar 5, 2008, at 11:40 AM, Jim Turner wrote:

    > But, I still appear to have an issue with defining a custom
    > getter/setter.  Defining a property as
    > @property (setter=mySetMethod:,getter=myMethod) id valueTest;
    > and sending my object a valueTest message, I get the unrecognized
    > selector sent to instance warning.
    >
    Again this behaves correctly.
    You've specified that the getter and setter are myMethod and
    mySetMethod: respectively.
    If you ask the compiler to synthesise the methods, those are what
    you'll get, and they'll access the 'valueTest' instance variable.
    You haven't specified a valueTest method anywhere...

    mmalc
  • On Mar 5, 2008, at 2:40 PM, Jim Turner wrote:

    > On Wed, Mar 5, 2008 at 12:00 PM, mmalc crawford
    > <mmalc_lists...> wrote:
    >>
    >> On Mar 5, 2008, at 9:34 AM, Jim Turner wrote:
    >>
    >>> I filed a bug (rdar://problems/5781977) as this doesn't appear to be
    >>> proper behavior.  I'd be happy to be told I'm wrong if you can point
    >>> out what I'm missing.
    >>
    >> I believe this behaves correctly.
    >> As stated in <http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/Articl
    es/chapter_5_section_5.html#
    >>> , "Key-value coding and declared properties are orthogonal
    >> technologies."
    >> KVC doesn't know about any custom setter you may have defined for a
    >> property.
    >>
    >> mmalc
    >>
    >>
    >
    > Hmm, it appears the developer documentation I have locally on my
    > machine is slightly out of date.  After reading that link (and the
    > updated description of setter= and getter=), I see now why what I'm
    > doing isn't working.  Properties and KVO/KVC aren't complimentary to
    > each other... although it'd be nice if they were.  I'll have to
    > re-work my object to get it to be properly compliant.
    >
    > But, I still appear to have an issue with defining a custom
    > getter/setter.  Defining a property as
    >
    > @property (setter=mySetMethod:,getter=myMethod) id valueTest;
    >
    > and sending my object a valueTest message, I get the unrecognized
    > selector sent to instance warning.  Reading (and re-reading several
    > times) http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/Articl
    es/chapter_5_section_3.html#/

    > /apple_ref/doc/uid/TP30001163-CH17-SW17
    > it appears that I don't need to define anything other than the
    > @property but unless I also place
    >
    > -(id) valueTest;
    > -(void) setValueTest:(id)_value;
    >
    > in the interface, the object can't find a method signature.
    >
    > This is a little more confusing that I originally thought. I
    > appreciate all the help, though.

    If you define a @property in the interface, then in the implementation
    you either need use @synthesize to have the compiler automatically
    generate a getter and setter, or use @dynamic to inform the compiler
    that you will provide the appropriately named getter and setter
    methods.  In neither case should there be a need to declare the
    getter and setter methods explicitly in your interface, since the
    @property directive does that for you.  See here for more info: http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/Articl
    es/chapter_5_section_1.html


    For example:

    @interface Person : NSObject
    {
      NSString *firstName;
    }
    @property(copy) NSString *firstName;
    @end

    @implementation Person
    @synthesize firstName;  // causes firstName and setFirstName: methods
    to be generated
    @end

    This defines Person with a KVC compliant firstName property.    You
    could now access the firstName property using either person.firstName
    and person.firstName=@"Joe", or [person firstName] and [person
    setFirstName:@"Joe"].

    If you need to define the accessors yourself because the auto-
    generated ones don't do what you want, then use @dynamic instead like
    this:

    @implementation Person
    @dynamic firstName;

    - (NSString*)firstName { ... }
    - (void)setFirstName:(NSString *)newName { ... }
    @end
  • On Mar 5, 2008, at 1:40 PM, Adam P Jenkins wrote:

    > If you define a @property in the interface, then in the
    > implementation you either need use @synthesize to have the compiler
    > automatically generate a getter and setter, or use @dynamic to
    > inform the compiler that you will provide the appropriately named
    > getter and setter methods.
    >
    There is no *need* to specify @dynamic.  In fact, doing so will
    conceal a bug (at least until runtime...) if you don't intend to
    create the appropriate methods at runtime (as do, for example, managed
    objects) but forget to provide an implementation.  If you don't
    specify @dynamic, then the compiler will warn you if you don't supply
    appropriate methods at compile time.

    > If you need to define the accessors yourself because the auto-
    > generated ones don't do what you want, then use @dynamic instead
    > like this:
    > @implementation Person
    > @dynamic firstName;
    >
    > - (NSString*)firstName { ... }
    > - (void)setFirstName:(NSString *)newName { ... }
    > @end

    It's perfectly reasonable also to do either:

    @implementation Person

    - (NSString*)firstName { ... }
    - (void)setFirstName:(NSString *)newName { ... }
    @end

    or, for example:

    @implementation Person
    @synthesize firstName;

    - (void)setFirstName:(NSString *)newName { ... }
    @end

    In the latter case, the compiler will just synthesise -firstName.

    One further issue for the sake of raising it:
    > @property (setter=mySetMethod:,getter=myMethod) id valueTest;
    >

    Note that this implies that the accessor methods are atomic.  It's
    comparatively rare (unless you're using GC) that Cocoa developers
    implement atomic accessor methods, so you'd typically specify:

    @property (nonatomic, setter=mySetMethod:,getter=myMethod) id valueTest;

    mmalc
  • On Mar 5, 2008, at 5:14 PM, mmalc crawford wrote:
    >
    > One further issue for the sake of raising it:
    >> @property (setter=mySetMethod:,getter=myMethod) id valueTest;
    >>
    >
    > Note that this implies that the accessor methods are atomic.  It's
    > comparatively rare (unless you're using GC) that Cocoa developers
    > implement atomic accessor methods, so you'd typically specify:
    >
    > @property (nonatomic, setter=mySetMethod:,getter=myMethod) id
    > valueTest;

    So for most non-GC code, properties should be specified using
    @property (nonatomic, ...)?

    I've seen a lot of Apple sample code that doesn't.  Should we be
    filing docs/sample code bugs, or just enabling GC?

    Bill
  • On Mar 5, 2008, at 2:56 PM, Bill Garrison wrote:

    >> Note that this implies that the accessor methods are atomic.  It's
    >> comparatively rare (unless you're using GC) that Cocoa developers
    >> implement atomic accessor methods, so you'd typically specify:
    >>
    >> @property (nonatomic, setter=mySetMethod:,getter=myMethod) id
    >> valueTest;
    >
    > So for most non-GC code, properties should be specified using
    > @property (nonatomic, ...)?
    > I've seen a lot of Apple sample code that doesn't.  Should we be
    > filing docs/sample code bugs, or just enabling GC?
    >
    If the documentation/sample code is not for GC and does not specify
    nonatomic and there is a provided implementation that is not atomic,
    then yes you should file a bug.

    A couple of examples to illustrate: If the sample defines

    @property (copy) NSString *string;

    then

    @synthesize string;

    that's fine.

    If it defines:

    @property (copy) NSMutableString *string;

    then

    @synthesize string;

    - (void)setString:(NSString *)newString {
        if (string != newString) {
            [string release];
            string = [newString mutableCopy];
        }
    }

    that would not be OK (the declaration should include nonatomic).

    mmalc
  • On Mar 5, 2008, at 2:56 PM, Bill Garrison wrote:

    > So for most non-GC code, properties should be specified using
    > @property (nonatomic, ...)?
    >
    To address this separately as a general point: see performance and
    threading considerations discussed at <http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/Articl
    es/chapter_5_section_3.html#//apple_ref/doc/uid/TP30001163-CH17-SW12
    >.

    mmalc
  • On Wed, Mar 5, 2008 at 4:14 PM, mmalc crawford <mmalc_lists...> wrote:
    >
    > On Mar 5, 2008, at 1:40 PM, Adam P Jenkins wrote:
    >
    >> If you define a @property in the interface, then in the
    >> implementation you either need use @synthesize to have the compiler
    >> automatically generate a getter and setter, or use @dynamic to
    >> inform the compiler that you will provide the appropriately named
    >> getter and setter methods.
    >>
    > There is no *need* to specify @dynamic.  In fact, doing so will
    > conceal a bug (at least until runtime...) if you don't intend to
    > create the appropriate methods at runtime (as do, for example, managed
    > objects) but forget to provide an implementation.  If you don't
    > specify @dynamic, then the compiler will warn you if you don't supply
    > appropriate methods at compile time.
    >
    >
    >> If you need to define the accessors yourself because the auto-
    >> generated ones don't do what you want, then use @dynamic instead
    >> like this:
    >> @implementation Person
    >> @dynamic firstName;
    >>
    >> - (NSString*)firstName { ... }
    >> - (void)setFirstName:(NSString *)newName { ... }
    >> @end
    >
    > It's perfectly reasonable also to do either:
    >
    >
    > @implementation Person
    >
    >
    > - (NSString*)firstName { ... }
    > - (void)setFirstName:(NSString *)newName { ... }
    > @end
    >
    >
    > or, for example:
    >
    >
    > @implementation Person
    > @synthesize firstName;
    >
    >
    > - (void)setFirstName:(NSString *)newName { ... }
    > @end
    >
    >
    > In the latter case, the compiler will just synthesise -firstName.
    >
    >
    > One further issue for the sake of raising it:
    >
    >> @property (setter=mySetMethod:,getter=myMethod) id valueTest;
    >>
    >
    > Note that this implies that the accessor methods are atomic.  It's
    > comparatively rare (unless you're using GC) that Cocoa developers
    > implement atomic accessor methods, so you'd typically specify:
    >
    > @property (nonatomic, setter=mySetMethod:,getter=myMethod) id valueTest;
    >
    >
    > mmalc
    >

    Ok first, mmalc, thank you for taking the time to point out exactly
    what I needed to see to understand where I was going wrong.  My
    problem stemmed from the misguided idea that properties were required
    for KVC/KVO.  Chris' comment about "using non-default names" makes
    much more sense now.

    Second, for my situation, I ended up with an interface that looks like this:

    @property (getter=getValueForBindings, setter=setValueForBindings:,
    assign, nonatomic) id value;

    And an implementation:

    -(void) setValueForBindings:(id)_value
    {
    [self willChangeValueForKey:@"value"];
    {
            BOOL didSetOK = [self setStringValue:(NSString *)_value];
                  // Do something with didSetOK
    }
    [self didChangeValueForKey:@"value"];
    }

    -(id) getValueForBindings
    {
    return( value );
    }

    Then binding my interface to the key 'valueForBindings'.  Not the
    prettiest, but it's required for my situation.

    Thanks again to everyone for all the help.

    --
    Jim
    http://nukethemfromorbit.com
  • On 06/03/2008, at 10:10 AM, Jim Turner wrote:

    > Ok first, mmalc, thank you for taking the time to point out exactly
    > what I needed to see to understand where I was going wrong.  My
    > problem stemmed from the misguided idea that properties were required
    > for KVC/KVO.  Chris' comment about "using non-default names" makes
    > much more sense now.
    >
    > Second, for my situation, I ended up with an interface that looks
    > like this:
    >
    > @property (getter=getValueForBindings, setter=setValueForBindings:,
    > assign, nonatomic) id value;
    >
    > And an implementation:
    >
    > -(void) setValueForBindings:(id)_value
    > {
    > [self willChangeValueForKey:@"value"];
    > {
    > BOOL didSetOK = [self setStringValue:(NSString *)_value];
    > // Do something with didSetOK
    > }
    > [self didChangeValueForKey:@"value"];
    > }
    >
    > -(id) getValueForBindings
    > {
    > return( value );
    > }
    >
    > Then binding my interface to the key 'valueForBindings'.  Not the
    > prettiest, but it's required for my situation.
    >
    > Thanks again to everyone for all the help.

    Why have you got calls to -willChangeValueForKey: and -
    didChangeValueForKey:? It should probably be done wherever value is
    changed, if it's not automatic. It's also not clear to me why you
    can't just name the methods setValue and value (and rename your other
    methods).

    On a separate note, I would personally avoid using identifiers
    beginning with underscores. I'm pretty sure they are reserved but even
    if they're not, I would avoid it.

    Kind regards,

    Chris
previous month march 2008 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