views:

464

answers:

3

This is an example from The Objective-C 2.0 Programming Language. I was just wondering, in the setter at the bottom, can I use value = [newValue retain] instead of value = [newValue copy] ?

    @interface MyClass : NSObject

{

    NSString *value;

}

@property(copy, readwrite) NSString *value;

@end



// assume using garbage collection

@implementation MyClass

@dynamic value;



- (NSString *)value {

    return value;

}



- (void)setValue:(NSString *)newValue {

    if (newValue != value) {

       value = [newValue copy];

    }

}

@end
A: 

No, your interface says copy. If somebody passes in an NSMutableString, you will get very different results from the two methods.

Chuck
By API, Church means your declaration of the `value` property. Either both should be `copy` or `retain`.
notnoop
so by using copy i can skip the type checking to avoid runtime error, is that the idea?
derrdji
A: 

It depends. If you use [newValue retain], another object may change the value of this NSString pointer. Normally, you do not like to have this behaviour.

swegi
+3  A: 

The quickest and safest thing to do would be to add @synthesize value to the top of your implementation, and the compiler will automatically generate these methods.

The issue of copy vs. retain hinges on the fact that you may be passed in a NSMutableString, which would change its value. If you have a setter for an 'immutable' type (string, set, array, dictionary), you need to use copy semantics. At first this may seem counterintuitive (why make a copy if it's immutable?) but the thing to realize is that your class wants to assume it is immutable, and what's passed in may not actually be immutable.

NSMutable classes implement the copy selector by returning an immutable version of what they represent. The immutable classes (NSString, etc) implement copy with a retain call. That is to say, they are very fast.

Your setter also needs to release value before assigning it a new value. The proper code is:

-(void)setValue:(NSString*)newvalue
{
    if (value != newvalue)
    {
        [value release];
        value = [newvalue copy];
    }
}

If you have complete control over all the classes that may call setValue: and are absolutely sure you won't be passing in NSMutableString, you can use retain, but it's best practices to use copy.

Jason
is it a good idea to always use copy? also, can i say @property(retain, copy, readwrite) NSString *value , and what would the effect be? thank you
derrdji
That wouldn't compile. It's a good idea to use copy when you expect/want the item to be immutable from the visibility of your class. If you have a property to something that does not represent a value (a UI outlet property, for example), use retain.
Jason