54

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.

swiftBoy
  • 33,793
  • 26
  • 129
  • 124
qstar
  • 701
  • 1
  • 8
  • 11
  • 29
    But why?? Please add a reason! – bobobobo Nov 02 '09 at 17:38
  • 15
    Simple: an NSMutableString is an NSString. If someone passes you a mutable string which you retain, they can then change it afterwards. And since your property was NSString type, you likely aren't expecting that behavior. By and large, immutable classes implement -copy by calling retain on themselves, so it's (usually) not costing you any memory unless you actually NEED that memory. – ipmcc Mar 18 '11 at 17:07
  • @ipmcc What about `readonly` properties (`@property (nonatomic, retain/assign/copy, readonly) NSString *myString;`), is it better to `retain`, `copy`, or `assign` those? – chown Dec 25 '11 at 16:58
  • 1
    With a readonly property, retain/copy/assign makes no difference to external callers, but should still accurately reflect how you're treating the underlying value internally to your class. This is important if you're using ARC and @synthesize to create your iVars, as the compiler will use your property declaration as the indication of how you want ARC to handle that value when automatically handing retain/release. – ipmcc Dec 25 '11 at 17:40
  • @ipmcc: This is not entirely true. I would have to verify it again but IIRC if a readonly object property is assign, the getter just returns the value of the iVar, if it is retain or copy, the getter returns the value of the iVar as `[[... retain] autorelease]`, which can be an important difference if you ever replace the value of the iVar somehow in your code. – Mecki May 14 '12 at 13:58
  • @RDC Why are you adding `ios` tag to questions that should be tagged only `objective-c`? – Sulthan Apr 01 '16 at 19:41

8 Answers8

68

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).

Art
  • 21,071
  • 27
  • 83
  • 97
Chuck
  • 222,660
  • 29
  • 289
  • 383
  • 11
    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 Sep 04 '09 at 21:07
  • 9
    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. – PeyloW Sep 04 '09 at 21:08
  • 1
    @Matt: Efreedom just has copies of SO questions, I'd suggest linking to the [original SO question](http://stackoverflow.com/questions/387959/nsstring-property-copy-or-retain) instead. – Hans Olsson Mar 16 '11 at 20:09
  • 2
    @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. – Peter Hosey Mar 20 '11 at 00:59
  • 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. ;-) – Slipp D. Thompson Apr 19 '13 at 09:38
  • @PeyloW: Why assign? why not weak? https://developer.apple.com/library/ios/documentation/cocoa/conceptual/ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html recommends using weak reference to avoid circular references. – gmuhammad Nov 21 '13 at 14:01
  • @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. – Chuck Nov 21 '13 at 18:28
  • @PeyloW, It looks like you're contradicting yourself. Should I use `copy` for classes with mutable variant or for __all__ objects? – Iulian Onofrei Feb 04 '16 at 10:18
19

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.

Axel
  • 1,646
  • 1
  • 16
  • 28
  • Thanks, this was very important! Following the advice in the top answers was still not retaining the value. Very important to do `self.name = ...` – ck_ Apr 13 '12 at 19:04
12

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.

fbrereto
  • 34,250
  • 17
  • 118
  • 176
  • ok...yeah, I think I'm sorta geting you. Please tell me in detail what you mean please. – qstar Sep 04 '09 at 17:23
  • because, if it's alive for the retain method, why not for the assign statement – qstar Sep 04 '09 at 17:27
  • 8
    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. – Dave DeLong Sep 04 '09 at 17:39
  • Ahh, nice answer. But then why not use it for other declarations such as for NSInteger types as well. @property(nonatomic, retain) NSInteger *name; – qstar Sep 04 '09 at 17:46
  • 2
    @qstar: NSInteger is not an object. – Chuck Sep 04 '09 at 17:47
  • 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 Sep 04 '09 at 17:48
  • Ahh, Thanks Chuck So primitives are always held in memory! – qstar Sep 04 '09 at 17:49
  • Actually, why doesn't the same memory management concept apply to primitive values as well? – qstar Sep 04 '09 at 18:52
  • 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. – fbrereto Sep 04 '09 at 20:52
  • 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. – Chuck Sep 04 '09 at 21:12
  • 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? – bobobobo Nov 02 '09 at 17:45
  • @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. – fbrereto Nov 02 '09 at 18:40
  • Understandable answer.Then Can you tell me what is the difference between Copy and Retain – Sat Mar 07 '11 at 06:08
9

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

andy boot
  • 10,179
  • 3
  • 47
  • 62
tbone
  • 13,914
  • 3
  • 31
  • 39
9

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.

chown
  • 48,838
  • 16
  • 128
  • 167
jem
  • 111
  • 1
  • 5
  • this is a very nice info @jem. For the first time, I think it's too much (comparing with `this` in Java) – swdev Aug 23 '11 at 15:54
8

After reading so many Articles, SO posts and made demo apps to check Variable property attributes, I decided to put all the attributes information together

  1. atomic //default
  2. nonatomic
  3. strong=retain //default
  4. weak= unsafe_unretained
  5. retain
  6. assign //default
  7. unsafe_unretained
  8. copy
  9. readonly
  10. readwrite //default

so below is the detailed article link where you can find above mentioned all attributes, that will defiantly help you. Many thanks to all the people who give best answers here!!

Variable property attributes or Modifiers in iOS

  1. retain = strong
    • it is retained, old value is released and it is assigned
    • retain specifies the new value should be sent -retain on assignment and the old value sent -release
    • retain is the same as strong.
    • apple says if you write retain it will auto converted/work like strong only.
    • methods like "alloc" include an implicit "retain"

Example:

@property (nonatomic, retain) NSString *name;

@synthesize name;
  1. assign
    • assign is the default and simply performs a variable assignment
    • assign is a property attribute that tells the compiler how to synthesize the property's setter implementation
    • I would use assign for C primitive properties and weak for weak references to Objective-C objects.

Example:

@property (nonatomic, assign) NSString *address;

@synthesize address;
swiftBoy
  • 33,793
  • 26
  • 129
  • 124
3

Google's Objective-C Style Guide covers this pretty well:

Setters taking an NSString, should always copy the string it accepts. Never just retain the string. This avoids the caller changing it under you without your knowledge. Don't assume that because you're accepting an NSString that it's not actually an NSMutableString.

funroll
  • 31,708
  • 7
  • 49
  • 56
2

Would it be unfortunate if your class got this string object and it then disappeared out from under it? You know, like the second time your class mentions that object, it's been dealloc'ed by another object?

That's why you want to use the retain setter semantics.

Dan Ray
  • 21,345
  • 6
  • 61
  • 86
  • Ok. So why would you ever *not* use `retain`? – Madbreaks Dec 19 '12 at 20:56
  • 2
    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). – Dan Ray Dec 20 '12 at 18:06
  • @DanRay neither object getting deallocated only if the Object B(had retained delegate of Object A) released in Object A's dealloc. – OzBoz Feb 15 '13 at 18:05