NSString property: copy or retain?

前端 未结 10 993
予麋鹿
予麋鹿 2020-11-22 02:53

Let\'s say I have a class called SomeClass with a string property name:

@interface SomeClass : NSObject
{
    NSString* name;
}

@p         


        
相关标签:
10条回答
  • 2020-11-22 02:57

    You should use copy all the time to declare NSString property

    @property (nonatomic, copy) NSString* name;
    

    You should read these for more information on whether it returns immutable string (in case mutable string was passed) or returns a retained string (in case immutable string was passed)

    NSCopying Protocol Reference

    Implement NSCopying by retaining the original instead of creating a new copy when the class and its contents are immutable

    Value Objects

    So, for our immutable version, we can just do this:

    - (id)copyWithZone:(NSZone *)zone
    {
        return self;
    }
    
    0 讨论(0)
  • 2020-11-22 03:00

    For attributes whose type is an immutable value class that conforms to the NSCopying protocol, you almost always should specify copy in your @property declaration. Specifying retain is something you almost never want in such a situation.

    Here's why you want to do that:

    NSMutableString *someName = [NSMutableString stringWithString:@"Chris"];
    
    Person *p = [[[Person alloc] init] autorelease];
    p.name = someName;
    
    [someName setString:@"Debajit"];
    

    The current value of the Person.name property will be different depending on whether the property is declared retain or copy — it will be @"Debajit" if the property is marked retain, but @"Chris" if the property is marked copy.

    Since in almost all cases you want to prevent mutating an object's attributes behind its back, you should mark the properties representing them copy. (And if you write the setter yourself instead of using @synthesize you should remember to actually use copy instead of retain in it.)

    0 讨论(0)
  • 2020-11-22 03:04

    Copy should be used for NSString. If it's Mutable, then it gets copied. If it's not, then it just gets retained. Exactly the semantics that you want in an app (let the type do what's best).

    0 讨论(0)
  • 2020-11-22 03:07

    Through this example copy and retain can be explained like:

    NSMutableString *someName = [NSMutableString stringWithString:@"Chris"];
    
    Person *p = [[[Person alloc] init] autorelease];
    p.name = someName;
    
    [someName setString:@"Debajit"];
    

    if the property is of type copy then ,

    a new copy will be created for the [Person name] string that will hold the contents of someName string. Now any operation on someName string will have no effect on [Person name].

    [Person name] and someName strings will have different memory addresses.

    But in case of retain,

    both the [Person name] will hold the same memory address as of somename string, just the retain count of somename string will be incremented by 1.

    So any change in somename string will be reflected in [Person name] string.

    0 讨论(0)
  • 2020-11-22 03:10

    I try to follow this simple rule:

    • Do I want to hold on to the value of the object at the point in time when I am assigning it to my property? Use copy.

    • Do I want to hold on to the object and I don't care what its internal values currently are or will be in the future? Use strong (retain).

    To illustrate: Do I want to hold on to the name "Lisa Miller" (copy) or to I want to hold on to the person Lisa Miller (strong)? Her name might later change to "Lisa Smith", but she will still be the same person.

    0 讨论(0)
  • 2020-11-22 03:16

    For strings in general, is it always a good idea to use the copy attribute instead of retain?

    Yes - in general always use the copy attribute.

    This is because your NSString property can be passed an NSString instance or an NSMutableString instance, and therefore we can not really determine if the value being passed is an immutable or mutable object.

    Is a "copied" property in any way less efficient than such a "retain-ed" property?

    • If your property is being passed an NSString instance, the answer is "No" - copying is not less efficient than retain.
      (It's not less efficient because the NSString is smart enough to not actually perform a copy.)

    • If your property is passed an NSMutableString instance then the answer is "Yes" - copying is less efficient than retain.
      (It's less efficient because an actual memory allocation and copy must occur, but this is probably a desirable thing.)

    • Generally speaking a "copied" property has the potential to be less efficient - however through the use of the NSCopying protocol, it's possible to implement a class which is "just as efficient" to copy as it is to retain. NSString instances are an example of this.

    Generally (not just for NSString), when should I use "copy" instead of "retain"?

    You should always use copy when you don't want the internal state of the property changing without warning. Even for immutable objects - properly written immutable objects will handle copy efficiently (see next section regarding immutability and NSCopying).

    There may be performance reasons to retain objects, but it comes with a maintenance overhead - you must manage the possibility of the internal state changing outside your code. As they say - optimize last.

    But, I wrote my class to be immutable - can't I just "retain" it?

    No - use copy. If your class is really immutable then it's best practice to implement the NSCopying protocol to make your class return itself when copy is used. If you do this:

    • Other users of your class will gain the performance benefits when they use copy.
    • The copy annotation makes your own code more maintainable - the copy annotation indicates that you really don't need to worry about this object changing state elsewhere.
    0 讨论(0)
提交回复
热议问题