18

I am new to iOS development in general and have never dealt with manual reference counting (retain, release, autorelease). As such I don't have a good understanding of what magic ARC is performing.

I thought I understood until I was asked what type of ownership (weak, strong, assign, etc) should be given to a readonly property pointing at an object, such as:

@property (readonly,nonatomic) NSString* name;

I read here Questions about a readonly @property in ARC that leaving off the strong/weak won't actually compile unless you specify a backing variable when you @synthesize the property; I just so happened to be specifying a backing ivar like this:

@synthesize name = _name;

Now I understand that the default 'lifetime qualifier' of a variable is strong, from here: http://developer.apple.com/library/ios/releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html#//apple_ref/doc/uid/TP40011226-CH1-SW4

So to cut a long story short - I am indirectly defining my property as (readonly,nonatomic,strong) as the _name ivar is implicitly declared as __strong.

I have a few questions:

  1. Is strong the correct lifetime qualifier to use? I assume that it is, otherwise the object backing my NSString* wouldn't be owned anywhere and would thus be freed automatically (coming from Java land this makes sense as all references are strong by default).

  2. Are there any other modifiers which make sense in this situation, such as copy or assign?

  3. Does declaring the property as (readonly,nonatomic,strong) and (readonly,nonatomic) make any difference to the code which consumes the property? eg. does declaring it without the strong keyword cause the object pointer to be stored as __unsafe_unretained where the strong property would be stored in a __strong pointer?

Thanks!

EDIT

So as I understand now, the following applies to readonly properties:

  • For non-NSObject* types (int, float, void*, etc) use (readonly, assign).
  • For object pointers, use (readonly, strong) or (readonly, copy) - these function the same for readonly properties but you may want the copy semantics if you extend/subclass and redeclare the property as readwrite.
  • For object pointers, (readonly, weak) only makes sense if you are going to be storing an already weak pointer in that property (that pointer must be strong elsewhere or the object will be deallocated).
Community
  • 1
  • 1
Wayne Uroda
  • 5,025
  • 4
  • 30
  • 35
  • Note that "strong" is implied, so if you extend a readonly specified `(readonly)` with `(strong)` it will work, but `(copy)` won't. Instead you'd see "ARC forbids synthesizing a property ... with unspecified ownership or storage attribute." In this case you need to be explicit in the header definition `(readwrite, copy)`. This tripped me up for a few minutes. – Ben Flynn Sep 01 '14 at 05:06

3 Answers3

12
  1. strong is correct to use if you want to keep a strong (owning) reference to whatever it is that you are pointing to. Usually, you do want strong, but in order to prevent circular references (particularly in parent/child relationships where if the parent points to the child and the child points to the parent, they will never be released) you sometimes need to use weak references. Also, if you want to keep a pointer to an object that you don't own but want it to be valid only as long as it exists, then you want to use a weak pointer because when it gets deallocated by the owner, your pointer will automatically get set to nil and won't be pointing to memory that it shouldn't be.

  2. assign is used with scalar values, and is the default setter. copy makes sense if you want to automatically make a copy of the object and set your pointer to the copy instead of pointing to the original object. It only makes sense to do this if you have a specific need (usually because you don't want the object to mutate on you).

  3. The link that you provided which shows that __strong is the default (and therefore you don't need to specify it) refers to variables and not to declared properties. The default for declared properties is assign so it certainly will make a difference. If you were wanting assign however, it makes no difference whether you specify it or not (other than just to be clear that it is what you wanted). EDIT: However, as Jacques pointed out, this is changing with LLVM 3.1 and the default is changing from assign to strong. In this case, it makes absolutely no difference whether or not you specify strong and can leave it out if you want. Personally I think that it is good to spell it out (especially since there is a conflict between different versions) so that everyone looking at the code is on the same page. Others may disagree on this point though. :)

I would suggest reading the Declared Properties section of The Objective-C Programming Language here: <document removed by Apple with no direct replacement>.

lnafziger
  • 25,760
  • 8
  • 60
  • 101
  • They actually changed the default for properties, too, as of the next release (3.1) of Clang: http://clang.llvm.org/docs/AutomaticReferenceCounting.html#ownership.spelling.property – jscs May 22 '12 at 01:43
  • Interesting... Now it is different between ARC and non-ARC code. Thanks @JacquesCousteau! – lnafziger May 22 '12 at 01:47
  • 1
    I have already read the link you gave many times, unfortunately I find it very light on useful information which is why I am asking here. As to your answer, I don't feel it addresses my question which is in regards to readonly properties specifically. – Wayne Uroda May 23 '12 at 00:10
  • Well, I answered the question (in addition to providing the link) because you asked it here. :) As far as my answer, everything here applies to declared properties whether they are readonly or not. There isn't anything special about readonly, other than the fact that a setter will not be supplied for you when you @synthesize it. – lnafziger May 23 '12 at 00:58
  • I understand that but in your answer you say that copy makes sense in some situations, but does it ever make sense for a readonly property? I am already confused, that's why I hoped to limit the explanation to readonly properties. – Wayne Uroda May 23 '12 at 01:26
  • Gotcha. In the case of readonly it usually won't matter since no setter is created for you (which is the only place that it would be used). However, as @KenThomases pointed out, you **can** redeclare it as read-write and it would make a difference at that point. – lnafziger May 23 '12 at 01:29
  • Excellent. So for a readonly property, copy===strong, until such time as you subclass or extend to redeclare the property as readwrite (as I understand it). – Wayne Uroda May 24 '12 at 01:48
  • Kind of. Copy is just ignored for read only, until then. And yes, strong is implied so that's what you end up wit. – lnafziger May 24 '12 at 01:54
  • This article probably covers similar topics to the one that vanished: http://developer.apple.com/library/ios/documentation/cocoa/conceptual/ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html – dooleyo Aug 14 '13 at 06:08
7

One additional point: properties can get redeclared from readonly to readwrite. For example, a subclass may make a read-only property from the superclass read-write, similar to how many Cocoa classes have subclasses that add mutability. Likewise, a property may be publicly read-only but the class may redeclare it read-write for internal use in a class extension. So, when the class sets its own property it can take advantage of a synthesized setter that does memory management properly and emits appropriate Key-Value Observing change notifications.

As things currently stand, all of the other attributes of the property have to be consistent. It's conceivable that the compiler could relax this requirement. (Some consider it a bug.) Anyway, that's one reason to declare a readonly property with an ownership attribute like strong, copy, or weak – so that it will match the readwrite redeclaration elsewhere.

With regard to your question 3, are you asking if the ownership qualifier affects code which calls the getter? No, it doesn't.

Ken Thomases
  • 88,520
  • 7
  • 116
  • 154
  • 1
    So the strong/weak modifier doesn't make any difference to a readonly property other than changing the lifetime qualifier of the synthesized ivar, is that correct? – Wayne Uroda May 23 '12 at 00:13
0

These 2 lines of code work for me:

.h file:

@property (nonatomic, readonly, copy) NSString *username;

.m file:

@property (nonatomic, readwrite, copy) NSString *username;
Golden Thumb
  • 2,531
  • 21
  • 20