Following on from my first post about looking at how ARC works under the hood I thought I would share another little snippet that I found interesting. This time I was wondering what happened when you pulled an object out of an array and returned it from a method. Pre-ARC, you would retain the object then return it autoreleased. With ARC we can get rid of those memory management calls but it just feels wrong. So I decided to check ARC was doing the right thing.
Consider this class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
In non-ARC land, the call to removeLastObject
would release the object that was in the array and then if that was the last reference to it, it would dealloc
the object meaning that we return a dead object. So we would retain lastObject
and then return it with an autorelease.
But this scared me not doing this, even though I knew full well that ARC should be doing its job. I think I thought this because naively I thought that ARC would parse the method line by line. If it did then I thought it might not necessarily add in a retain because when we get a reference to the last object, ARC doesn’t know it needs to add a retain because well, why would it necessarily have to?
That’s where I was wrong. Obviously what ARC does is it will add in a retain once we get a reference to that object and then when that variable goes out of scope it adds a release or in our case, because we are returning it and the method name does not start with new
or copy
, it autoreleases it.
Let’s see what that code compiled to:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
Well, there we go. ARC has done a fine job for us. What it’s actually done is added a call to objc_retainAutoreleaseReturnValue
which means it has noticed it needs to retain a value that was returned autoreleased which must be an ARC optimisation that will just pull the object once from the autorelease pool rather than actually performing a retain. Then at the end of the method it calls objc_autoreleaseReturnValue
which must do the work of autoreleasing the value we’re returning.
This is just another example of how to look at what ARC is doing under the hood. The more I use ARC, the more I realise how useful it is. It makes code less prone to memory management errors and allows for optimisations such as the one shown here of retaining an autoreleased return value.