Why are Objective-C delegates usually given the property assign instead of retain? - objective-c

I'm surfing through the wonderful blog maintained by Scott Stevenson, and I'm trying to understand a fundamental Objective-C concept of assigning delegates the 'assign' property vs 'retain'. Note, the both are the same in a garbage collected environment. I'm mostly concerned with a non-GC based environment (eg: iPhone).
Directly from Scott's blog:
"The assign keyword will generate a setter which assigns the value to the instance variable directly, rather than copying or retaining it. This is best for primitive types like NSInteger and CGFloat, or objects you don't directly own, such as delegates."
What does it mean that you don't directly own the delegate object? I typically retain my delegates, because if I don't want them to go away into the abyss, retain will take care of that for me. I usually abstract UITableViewController away from its respective dataSource and delegate also. I also retain that particular object. I want to make sure it never goes away so my UITableView always has its delegate around.
Can someone further explain where/why I'm wrong, so I can understand this common paradigm in Objective-C 2.0 programming of using the assign property on delegates instead of retain?
Thanks!

The reason that you avoid retaining delegates is that you need to avoid a retain cycle:
A creates B
A sets itself as B's delegate
…
A is released by its owner
If B had retained A, A wouldn't be released, as B owns A, thus A's dealloc would never get called, causing both A and B to leak.
You shouldn't worry about A going away because it owns B and thus gets rid of it in dealloc.

Because the object sending the delegate messages does not own the delegate.
Many times, it's the other way around, as when a controller sets itself as the delegate of a view or window: the controller owns the view/window, so if the view/window owned its delegate, both objects would be owning each other. This, of course, is a retain cycle, similar to a leak with the same consequence (objects that should be dead remain alive).
Other times, the objects are peers: neither one owns the other, probably because they are both owned by the same third object.
Either way, the object with the delegate should not retain its delegate.
(There's at least one exception, by the way. I don't remember what it was, and I don't think there was a good reason for it.)
Addendum (added 2012-05-19): Under ARC, you should use weak instead of assign. Weak references get set to nil automatically when the object dies, eliminating the possibility that the delegating object will end up sending messages to the dead delegate.
If you're staying away from ARC for some reason, at least change assign properties that point to objects to unsafe_unretained, which make explicit that this is an unretained but non-zeroing reference to an object.
assign remains appropriate for non-object values under both ARC and MRC.

Note that when you have a delegate that's assign, it makes it very important to always set that delegate value to nil whenever the object is going to be deallocated - so an object should always be careful to nil out delegate references in dealloc if it has not done so elsewhere.

One of the reason behind that is to avoid retain cycles.
Just to avoid the scenario where A and B both object reference each other and none of them is released from memory.
Acutally assign is best for primitive types like NSInteger and CGFloat, or objects you don't directly own, such as delegates.

Related

Why would app crash if delegate uses assign instead of weak?

I have seen report that if a delegate uses assign instead of weak, the app crashes. Why?
Example: RestKit
With ARC a weak ivar will be automatically set to nil when the ivar object is deallocated. That means that if your delegate is destroyed and you try to message the delegate you'll just message nil, which has no effect. If the delegate ivar was merely assign then you would message some chunk of memory that no longer contained a valid object.
The only difference between assign and weak is that weak does extra work to avoid some common crashing bugs. The drawback, however, is that assign has much better performance than weak.
Specifically, when an object is released, any weak property pointing to it will be set to nil. Any assign property pointing to it will be left pointing at the object that is no-longer used.
And some other object is likely to be placed at the same location in memory as the old object, so suddenly instead of an instance of MyDelegate you might have a UIImage object in the same location in memory, or perhaps a float value, or anything at all.
So you should always use weak, for everything. But if you run into performance problems, check if weak is the cause, and consider switching to assign after learning how to avoid those crashing bugs.
For a delegate you should pretty much always use weak. Normally you'd only pick assign if you are dealing with millions of objects. Typically that doesn't happen with delegates.

Conflict between memory management descriptions in ObjC book and official docs

I'm trying to learn/understand what happens and why when working with or creating various objects. (Hopefully to LEARN from the docs.)
I'm reading "Programming in Objective-C 2.0" (2nd edition, by Steven Kochan). On page 408, in the first paragraph is a discussion of retain counts:
Note that its reference count then goes to 2. The addObject: method does this automatically; if you check your documentation for the addObject: method, you will see this fact described there.
So I read the addObject: docs:
Inserts a given object at the end of the array.
There, the description is missing, while other items, like arrayByAddingObject:, state it:
Returns a new array that is a copy of the receiving array with a given object added to the end.
Where in the reference does it indicate that addObject: increases the retain count? Given the presence of ARC, I should still understand what these methods are doing to avoid bugs and issues. What does ARC bring to this? (Going to read that again...)
Great question, I'm glad to see someone actually reading the docs and trying to understand them!
Since you are looking for how to research answers using Apple's documentation more so than the actual answer itself, here is how I found the answer:
First I look at the class reference for addObject: which is a method of NSMutableArray and there is no mention of memory management.
Then I look at the Overview section at the top... Hmmm, still no luck.
Since the behavior might be inherited from a parent class, I look at the Inherits from section at the top of the class reference and see that NSArray is the most immediate parent. Let's check there:
Under the Overview There is one small section about retain's:
Special Considerations
In most cases your custom NSArray class should conform to Cocoa’s
object-ownership conventions. Thus you must send retain to each object
that you add to your collection and release to each object that you
remove from the collection. Of course, if the reason for subclassing
NSArray is to implement object-retention behavior different from the
norm (for example, a non-retaining array), then you can ignore this
requirement.
Okay, I'm still not happy... Where next? The parent class of NSArray is NSObject and I know that it won't be covered there in this case (from experience) so I won't bother checking that. (If the parent was another class or something that might be covered by NSObject, I would keep moving up the tree until I found something.)
The Companion Guides usually contains a lot of good information for these types of classes. Let's try the first one, Collections Programming Topics.
The first section (after Overview) is Accessing Indexes and Easily Enumerating Elements: Arrays. Sounds promising! Click on Relevant Chapters: “Arrays: Ordered Collections”
There it is under Array Fundamentals along with a link to even more information:
And when you add an object to an NSMutableArray object, the object
isn’t copied, (unless you pass YES as the argument to
initWithArray:copyItems:). Rather, an object is added directly to an
array. In a managed memory environment, an object receives a retain
message when it’s added; in a garbage collected environment, it is
strongly referenced. When an array is deallocated in a managed memory
environment, each element is sent a release message. For more
information on copying and memory management, see “Copying
Collections.”
The book must be referring to out of date documentation because you are correct it doesn't mention anything about the retain count. It does in fact retain the object though. The way you need to think of it is not in terms of retain counts (which are useless) but rather ownership. Especially so when using ARC.
When you add an object to an NSMutableArray, it is taking ownership of that object (in ARC terminology it has a strong reference to it).
"What does ARC bring to this?"
ARC does nothing different. All ARC does (besides some optimization) is add the same release, retain, and autorelease statements that you would add yourself without using ARC. All you need to care about is that once you add an object to the array, it will live at least as long as the array.
And the arrayByAddingObject: method creates a new NSArray (or NSMutableArray) containing the object you're passing, and keeps a strong reference to the passed object. The actual array object that it creates has no references yet unless you assign it to either an ivar, property, or local variable. What you assign it to determines it's lifespan.
Basically even without ARC, it's best to think of object life-cycles in terms of ownership, ARC just formalizes that. So because of that, when using the frameworks, it doesn't matter when retains happen or don't happen, you are only responsible for your objects until you pass ownership to another object and you can trust that the framework will keep the object alive as long as it needs it.
Now of course you have to intuit what constitutes ownership. For instance delegate properties are often assign, or in ARC unsafe_unretained or weak, to prevent circular retains cycles (where two objects each retain each other), though are sometimes retained/strong so you need to look into those on a case by case basis.
And also in cases like key value observing and NSNotification observing the object you are observing does not retain the observer.
But those are really exceptions to the rule. Generally you can assume a strong reference.
Regarding this sentence above: "The actual array object that it creates has no references yet unless you assign it to either an ivar, property, or local variable. What you assign it to determines it's lifespan." I'll try to explain:
When you run this piece of code: [someArray arrayByAddingObject:someObject]; you've instantiated a new NSArray or NSMutableArray object (depending on which object type someArray is) but you haven't actually assigned it to any reference. That means that if you're using ARC, it may be immediately released afterwards, or if not using ARC, it will be released when it's autoreleasepool is drained (probably on the next iteration of that thread's runloop).
Now if instead you did this: NSArray *someOtherArray = [someArray arrayByAddingObject:someObject]; you now have a reference to the newly created array, called someOtherArray. In this case, this is a local variable who's scope is only within whichever set of { } it resides (so it could be inside an if statement, a loop, or a method. Now if you do nothing else with it, it will die sometime after it's scope ends (it isn't guaranteed to die right away, but that isn't important, you just can't assume it lives longer).
Now if in your class you have an iVar (instance variable) declared in the header like NSArray *someOtherArray; (which is strong by default in ARC) and you run someOtherArray = [someArray arrayByAddingObject:someObject]; somewhere in your class, the object will live until you either remove the reference (someOtherArray = nil), you overwrite the reference (someOtherArray = someThirdArray), or the class is deallocated. If you were not using ARC, you would have to make sure to retain that to achieve the same effect (someOtherArray = [[someArray arrayByAddingObject:someObject] retain]; which is essentially what ARC is doing behind the scenes).
Or you may have a property declared instead like #property (nonatomic, strong) NSArray *someOtherArray in which self.someOtherArray = [someArray arrayByAddingObject:someObject]; would achieve the same effect but would use the proprety accessor (setSomeOtherArray:) or you could still use someOtherArray = [someArray arrayByAddingObject:someObject]; to set the iVar directly (assuming you #synthesized it).
Or assuming non-ARC, you might have declared the property like #property (nonatomic, retain) NSArray *someOtherArray in which self.someOtherArray = [someArray arrayByAddingObject:someObject]; would behave exactly as ARC would, but when setting the iVar directly you would still need to add that retain manually.
I hope that clears things up a bit, please let me know if there's anything I glossed over or left out.
As you mentioned in your comment, the key here is intuitively knowing when an object would be considered owned by another one or not. Luckily, the Cocoa frameworks follow a pretty strict set of conventions that allow you to make safe assumptions:
When setting an NSString property of a framework object (say the text property of a UILabel for example) it is always copied (if anyone knows of a counter-example, please comment or edit). So you don't have to worry about your string once you pass it. Strings are copied to prevent a mutable string from being changed after it's passed.
When setting any other property other than delegate, it's (almost?) always retained (or strong reference in ARC)
When setting delegate properties, it's (almost?) always an assign (or weak reference) to prevent circular retain cycles. (For instance, object a has a property b that is strong referenced and b has a strong referenced delegate property. You set a as the delegate for b. Now a and b are both strongly referencing each other, and neither object will ever reach a retain count of 0 and will never reach it's dealloc method to dealloc the other object. NSURLConnection is a counter-example that does strongly reference it's delegate, because it's delegate is set via a method -- see that convention below -- and it's convention to nil out or release an NSURLConnection after it completes rather than in dealloc, which will remove the circular retain)
When adding to an array or dictionary, it's always retained (or strong reference).
When calling a method and passing block(s), they are always copied to move them from the stack (where they are initially created for performance purposes) into the heap.
Methods that take in object parameters and don't return a result immediately are (always? I can't think of any that don't) either copying or retaining (strong referencing) the parameters that you pass to ensure that the method can do what it needs to with them. For instance, NSURLConnection even retains it's delegate because it's passed in via a method, whereas when setting the delegate property of other objects will not retain, as that is the convention.
It's suggested that you follow these same conventions in your own classes as well for consistency.
Also, don't forget that the headers of all classes are available to you, so you can easily see whether a property is retain or assign (or strong or weak). You can't check what methods do with their parameters, but there's no need because of the convention that parameters are owned by the receiver.
In general, you should look in the "most global" spot for information about anything in the Cocoa APIs. Since memory management is pervasive across the system APIs and the APIs are consistent in their implementation of the Cocoa memory management policy, you simply need to read and understand the Cocoa memory management guide.
Once understood, you can safely assume that all system APIs implement to that memory management policy unless explicitly documented otherwise.
Thus, for NSMutableArray's addObject: method, it would have to retain the object added to the array or else it would be in violation of that standard policy.
You'll see this throughout the documentation. This prevents every method's documentation from being a page or more long and it makes it obvious when the rare method or class implements something that is, for whatever reason (sometimes not so good), an exception to the rule.
In the "Basic Memory Management Rules" section of the memory management guide:
You can take ownership of an object using retain.
A received object is normally guaranteed to remain valid within the
method it was received in, and that method may also safely return the
object to its invoker. You use retain in two situations: (1) In the
implementation of an accessor method or an init method, to take
ownership of an object you want to store as a property value; and (2)
To prevent an object from being invalidated as a side-effect of some
other operation (as explained in “Avoid Causing Deallocation of
Objects You’re Using”).
(2) is the key; an NS{Mutable}Array must retain any added object(s) exactly because it needs to prevent the added object(s) from being invalidated due to some side-effect. To not do so would be divergent from the above rule and, thus, would be explicitly documented.

Can I just release the top object (iPhone)?

If I release the object that's holding a reference to the variable that I need to release, is that sufficient? Or must I release at every level of the containment hierarchy? I fear that my logic comes from working with a garbage collector for too long.
For instance, I assigned to this property of a UIPickerView instance by hand instead of using IB
#property(nonatomic, assign) id<UIPickerViewDelegate> delegate
Since it's an assign property, I can't just release the reference after I assign it. When I finally release my UIPickerView instance, do I need to do this:
[singlePicker.delegate release];
[singlePicker release];
or is the second line sufficient?
Also: Are these assign properties the norm, or is that mostly for Interface Builder? I thought that retain properties were the normal thing to expect.
The properties are declared assign instead of retain for a reason - delegates are not owned by their holders and they don't call release on them. Otherwise there would be a problem with circular references. You however have to call release on the object you use as the delegate somewhere if you own them.
If delegates were retained, imagine the following situation:
a takes b as a delegate, retains b
b takes a as a delegate, retains a
Now you have a circular reference - without ugly cleanup code that explicitly tells them to release their delegates, both of the objects will never be deallocated.
The subject is treated in Delegation and the Cocoa Application Frameworks:
Delegating objects do not (and should not) retain their delegates. However, clients of delegating objects (applications, usually) are responsible for ensuring that their delegates are around to receive delegation messages. To do this, they may have to retain the delegate in memory-managed code. This precaution applies equally to data sources, notification observers, and targets of action messages. Note that in a garbage-collection environment, the reference to the delegate is strong because the retain-cycle problem does not apply.

Objective-C Delegate Pointers

If we write the following code:
ExplorerAppDelegate * appDelegate = (ExplorerAppDelegate *)[[UIApplication sharedApplication] delegate];
This makes a reference to the original delegate pointer, but:
Does it increase the reference count?
Do we have to explicitly call as [ExplorerAppDelegate retain] right after, or not at all?
What's happening, exactly?
After we've used this, we should also do a [ExplorerAppDelegate release] in the dealloc method, right?
No, it does not increase the retain count.
The convention in Objective-C is that objects you are given should be memory managed by yourself - but in the case of obtaining a shared common resource like the app delegate, the memory is maintained elsewhere and of course (with this being the app delegate) you know that it will always be "alive" as long as your class is... so there is no need to retain the reference.
In most uses of delegates, instead of fetching a delegate you are given one, and that reference is not retained either. In that case whoever gave you the delegate is also responsive for clearing out the delegate link before the delegate is released.
The reason you don't want to generally retain delegate references is that it can prevent some objects from being deallocated, for instance if one class is a delegate of a class that ues the other class as a delegate.
The reference count will not be increased
You should retain it if you want to be sure that it isn't deallocated while you have a pointer to it
You should only release it if you retained it
So basically, if you're only using the object in a single function, you probably don't need retain or release it. If it exists when you get it, then it's (probably) not going to be deallocated by the end of the function. If you're keeping it around, in an ivar (member variable) for example, then you should retain it and release it later.
See the "Weak References to Objects" in Memory Management Programming Guide for Cocoa for the official answer. Pointers to delegates are one of the possible exception cases to the memory management rules.

How do I find out if I need to retain or assign an property?

Are there any good rules to learn when I should use retain, and when assign?
Assign is for primitive values like BOOL, NSInteger or double. For objects use retain or copy, depending on if you want to keep a reference to the original object or make a copy of it.
The only common exception is weak references, where you want to keep a pointer to an object but can't retain it because of reference cycles. An example of this is the delegate pattern, where an object (for example a table view) keeps a pointer to its delegate. Since the delegate object retains the table view, having the table view retain the delegate would mean neither one will ever be released. A weak reference is used in this case instead. In this situation you would use assign when you create your property.
I would think that when working with objects you would almost always use retain instead of assign and when working with primitive types, structs, etc, you would use assign (since you can't retain non-objects). That's because you want the object with the property deciding when it is done with the object, not something else. Apple's Memory Management Guide states this:
There are times when you don’t want a
received object to be disposed of; for
example, you may need to cache the
object in an instance variable. In
this case, only you know when the
object is no longer needed, so you
need the power to ensure that the
object is not disposed of while you
are still using it. You do this with a
retain message, which stays the effect
of a pending autorelease (or preempts
a later release or autorelease
message). By retaining an object you
ensure that it won’t be deallocated
until you are done with it.
For discussion around using copy vs retain, see this SO question.
I know this was an old question, but I found these guidelines from the uber guru Matt Gallagher, super useful: http://cocoawithlove.com/2009/07/rules-to-avoid-retain-cycles.html. In my case, I had a "retain hell" of my own making for having a hard reference to a parent object.
If you intend to keep the object and use it, use retain. Otherwise, it may be released and you'll end up with errors with your code.