views:

124

answers:

2
- (void)setFirstName:(NSString*)firstNameValue {
    [self willChangeValueForKey:@"firstName"];
    [firstName release];
    firstName = firstNameValue;
    [firstName retain];
    [self didChangeValueForKey:@"firstName"];
}

Is that right? So the willChange... foobar didChange... block causes an KVO notification to fire?

+3  A: 

No, your implementation is not 100% correct. Think what happens if the firstName is currently set to a NSString-instance and the setter is called with that very same instance. First you will release the instance, than you will set the instance variable, which in this case dosen't change anything and than you try the retain the instance, but by that time it could very well been dealloced already.

It should be:

- (void)setFirstName:(NSString*)firstNameValue {
    [self willChangeValueForKey:@"firstName"];
    [firstNameValue retain];
    [firstName release];
    firstName = firstNameValue;
    [self didChangeValueForKey:@"firstName"];
}

or:

- (void)setFirstName:(NSString*)firstNameValue {
    if (firstNameValue != firstName) {
        [self willChangeValueForKey:@"firstName"];
        [firstName release];
        firstName = firstNameValue;
        [firstName retain];
        [self didChangeValueForKey:@"firstName"];
    }
}

The latter version has the additional advantage of not sending oberserver-notifications if the value is not really changed.

tonklon
No difference in your implementation other than sequence in the first case and the check for no-op in the second. Your down vote was unfair. Retain followed by assignment has the same effect as assigning then retaining which you do in the no-op example. What is most important is that the setter method retains, assigns or copies depending on the desired behavior. Delegate and primitive ivars use assignment.
falconcreek
Remember that retain and copy return id so [firstName release]; firstName = [firstNameValue retain];Or[firstName release]; firstName = [firstNameValue copy];Depending on the desired behavior will do the trick.
falconcreek
@falconcreek: You didn't read my answer. By the time you want to retain the firstNameValue could already be dealloced.
tonklon
+1, this is a very good point about setters, the "No difference .. other than sequence" **completely** misses the point. Please note that this is a nonatomic setter (i.e. `@property (nonatomic,retain)`), add appropriate locking for the atomic case.
mvds
The "no difference..." comment is actually incorrect, my apologies. More emphasis is needed on the **could be the same instance** which if released before the retain *will* cause a crash if the object sending the message does not have ownership of the object passed in. After further reading of the http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAccessorMethods.html#//apple_ref/doc/uid/TP40003539-SW1 "Memory Management Programming Guide", one could argue that the first version *should not* be used. After all this discussion... use @synthesize!!!
falconcreek
A: 

Yes - calling didChangeValueForKey: will notify all the observers that the value has changed.

Nick Dowell