Objective-C 101 (retain vs assign) NSString

66,448

Solution 1

There's no such thing as the "scope of an object" in Objective-C. Scope rules have nothing to do with an object's lifetime — the retain count is everything.

You usually need to claim ownership of your instance variables. See the Objective-C memory management rules. With a retain property, your property setter claims ownership of the new value and relinquishes ownership of the old one. With an assign property, the surrounding code has to do this, which is just as mess in terms of responsibilities and separation of concerns. The reason you would use an assign property is in a case where you can't retain the value (such as non-object types like BOOL or NSRect) or when retaining it would cause unwanted side effects.

Incidentally, in the case of an NSString, the correct kind of property is usually copy. That way it can't change out from under you if somebody passes in an NSMutableString (which is valid — it is a kind of NSString).

Solution 2

and don't forget to access it via

self.name = something;

because

name = something;

will not care about the generated setter/getter methods but instead assign the value directly.

Solution 3

Without retain there is no guarantee the NSString* you are setting name with will live any longer than the assignment statement itself. By using the retain property for the synthesized setter you're allowing it to tell the memory management system that there is at least one more object interested in keeping the NSString* around.

Solution 4

For those who are looking for it, Apple's documentation on property attributes is here.

Solution 5

The self. in:

self.name = something;

is important! Without it, you are accessing the variable directly and bypassing the setter.

The older style (correct me if I am wrong) would have been:

[self setName:something];

Anyway, this notation was the (vaguely familiar sounding) advice that I really needed when I went looking for proper @properties on NSStrings. Thanks Axel.

Share:
66,448
qstar
Author by

qstar

Updated on July 09, 2022

Comments

  • qstar
    qstar almost 2 years

    A 101 question

    Let's say i'm making database of cars and each car object is defined as:

    #import <UIKit/UIKit.h>
    
    @interface Car:NSObject{
        NSString *name;
    }
    
    @property(nonatomic, retain) NSString *name;
    

    Why is it @property(nonatomic, retain) NSString *name; and not @property(nonatomic, assign) NSString *name;?

    I understand that assign will not increment the reference counter as retain will do. But why use retain, since name is a member of the todo object the scope of it is to itself.

    No other external function will modify it either.

  • qstar
    qstar over 14 years
    ok...yeah, I think I'm sorta geting you. Please tell me in detail what you mean please.
  • qstar
    qstar over 14 years
    because, if it's alive for the retain method, why not for the assign statement
  • Dave DeLong
    Dave DeLong over 14 years
    The retain ensures that it will stay alive, whereas with assign, there is no guarantee of that. Retaining means that you own that object and as long as you own it, it will not be destroyed. Assign gives you no such guarantee.
  • qstar
    qstar over 14 years
    Ahh, nice answer. But then why not use it for other declarations such as for NSInteger types as well. @property(nonatomic, retain) NSInteger *name;
  • Chuck
    Chuck over 14 years
    @qstar: NSInteger is not an object.
  • qstar
    qstar over 14 years
    Opps I meant @property(nonatomic, retain) NSInteger modelID; Let me restat my argument. Why doesn't the same understanding apply for this case? I see often @property(nonatomic, assign) NSInteger modelID;
  • qstar
    qstar over 14 years
    Ahh, Thanks Chuck So primitives are always held in memory!
  • qstar
    qstar over 14 years
    Actually, why doesn't the same memory management concept apply to primitive values as well?
  • fbrereto
    fbrereto over 14 years
    Some types (like NSInteger) are not heap-allocated, so there is no memory that needs to be released. Note that NSInteger is a different type from NSNumber, which does need memory management.
  • PeyloW
    PeyloW over 14 years
    You should use copy instead of retain for all classes that has a mutable variant. Eg. NSAArray, NSSet, NSDictionary, NSData, NSCharacterSet, NSIndexSet, and NSString.
  • PeyloW
    PeyloW over 14 years
    As a rule of thumb all properties with object references should use copy or retain, with one exception; delegates are assign to avoid circular references.
  • Chuck
    Chuck over 14 years
    Whether it's allocated on the heap or not is beside the point. malloc(sizeof(int)) allocates from the heap, but you'll crash if you try to release that. NSInteger is not an object and thus doesn't respond to messages.
  • bobobobo
    bobobobo over 14 years
    What do you mean "no guarantee"? Do you mean the memory can just go away on you randomly causing bugs? Or do you mean if somebody did a [ release ] or [ dealloc ] on "the NSString* you are setting name with", then you would be s.o.l.? ALso this is a separate question but a [ dealloc ] will completely destroy the NSString regardless of ref count, T/F?
  • fbrereto
    fbrereto over 14 years
    @bobobobo: If you do not [retain] the NSString* it may be deallocated behind your back; your next dereference of it would be to undefined memory. [dealloc] should never be called from within your own code (other than to call [super dealloc] in your own [dealloc]) - all you should need to call is [retain] and [release], and the OS will call [dealloc] when appropriate.
  • Sat
    Sat about 13 years
    Understandable answer.Then Can you tell me what is the difference between Copy and Retain
  • Hans Olsson
    Hans Olsson about 13 years
    @Matt: Efreedom just has copies of SO questions, I'd suggest linking to the original SO question instead.
  • Nico
    Nico about 13 years
    @PeyloW: Not just delegates; anything that is not an owning relationship should use assign rather than copy or retain. Paths down the object graph should be owning; paths up the graph (where included) should be non-owning. Otherwise, you will create circular references without having a delegate in the circle.
  • swdev
    swdev over 12 years
    this is a very nice info @jem. For the first time, I think it's too much (comparing with this in Java)
  • ck_
    ck_ about 12 years
    Thanks, this was very important! Following the advice in the top answers was still not retaining the value. Very important to do self.name = ...
  • Madbreaks
    Madbreaks over 11 years
    Ok. So why would you ever not use retain?
  • Dan Ray
    Dan Ray over 11 years
    If you're creating a .delegate property, the delegate will probably retain YOU. If you retain it back, you're creating a dependency loop that will result in neither object ever getting deallocated. Of course with ARC, this question is obsolete (we use "weak" and "strong" to imply something similar these days).
  • iDev
    iDev over 11 years
    That link is no longer available.
  • OzBoz
    OzBoz about 11 years
    @DanRay neither object getting deallocated only if the Object B(had retained delegate of Object A) released in Object A's dealloc.
  • Slipp D. Thompson
    Slipp D. Thompson about 11 years
    Technically, I wouldn't say there's no such thing as object lifetime scopes in Objective-C. I would say the only scope-end is the autorelease pool's clean-up, which happens right in the main run loop and never in the middle of any Objective-C code. But perhaps that's just a bit too technical. ;-)
  • gmuhammad
    gmuhammad over 10 years
    @PeyloW: Why assign? why not weak? developer.apple.com/library/ios/documentation/cocoa/conceptu‌​al/… recommends using weak reference to avoid circular references.
  • Chuck
    Chuck over 10 years
    @gmuhammad: This question was about retain vs. assign because strong and weak properties didn't exist in 2009. You're right that you would generally use weak these days.
  • Iulian Onofrei
    Iulian Onofrei over 8 years
    @PeyloW, It looks like you're contradicting yourself. Should I use copy for classes with mutable variant or for all objects?