Hi all, when I declare a property, something like:

@property(readwrite, copy, nonatomic) NSString *foo;

I will synthesize it with:

@synthesize foo;

But then I want to do some special processing when the value is set, so I 
implement my setter:

- (void)setFoo:(NSString *)aFoo {
    [self willChangeValueForKey:@"foo"];
    [foo autorelease];
    foo = [aFoo retain];
    [self didChangeValueForKey:@"foo"];
    [self 
doSomeMoreProcessingThatShouldHappenAfterAllTheObserversKnowTheNewValue];
}

I assumed from the documentation and examples that since I was providing my own 
implementation method, that I would have to include the willChange and 
didChange methods at appropriate points in my code, but I have just discovered 
that when I do:

anObject.foo = @"something";

I get two prior notifications - one from the internals of the system, and one 
from my willChange call, and two notifications after the change - one from my 
didChange and one from the system.

So I thought this must because I used @synthesize as well as providing my own 
method, so I implemented a getter and removed the @synthesize. The behavior 
didn't change.

I double checked this by removing my willChange and didChange methods, and now 
the prior and after notifications only got sent once.

One purpose of mentioning this is that given the fact that I have come across 
code from several places where they did what I did and had the willChange and 
didChange code in their setters, others may need to look back at their code and 
make appropriate changes.

But the big thing for me is that I have a number of places throughout my 
application where I need to have the changes made, the didChange notification 
acted on by the observers, and then some other code run.

I therefore wanted to use the setter, but not have to change the name of it, so 
that bindings would still work, so I changed my property declaration to be 
readonly, and declared a setFoo: method. I thought that declaring it would make 
it not call the willChange and didChange behind the scenes, but unfortunately, 
even with a readonly declaration, when I used anObject.foo = @"something", it 
still called the prior and after KVO methods. So I thought I would explicitly 
call setFoo: instead of using dot notation, but that made no difference. On the 
off chance there was something else going on, I also turned off 
accessesInstanceVariablesDirectly, but that made no difference.

So I thought I would just remove the property declarations altogether, and just 
code my accessors myself, but it still called the built in KVO methods. 

Therefore my conclusion is that as soon as you add a KVO observation on 
anything, it triggers the prior and after notifications whenever the setter is 
called. This of course makes sense, but still leaves me with the original 
problem: I need some way to have the KVO notifications called *once only*, and 
yet have my setters able to call other methods after the KVO notifications have 
been sent. It is not possible for this to be done with 
performSelector:withObject:afterDelay: or anything similar, since these methods 
need to be called immediately after the after change notification.

I know I could get it to call the KVO notifications at only the right places by 
coding my own methods like -(void)changeFooTo:, but I do not want to change the 
name of my setters because that would break my bindings. 

Are there any recommendations on the best approach for being able to have the 
setter able to do what it needs with the KVO and then calling other methods, 
without breaking bindings?

I can't believe I have misunderstood this for so long, and never noticed what 
was happening until now!

Thanks

Gideon








_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to