Why doesn't the Objective-c runtime set dealloc'd object instances to nil? - objective-c

Sometimes I set objects to nil after releasing them to avoid crashes due to unexpected messages sent to dealloc'd objects.
Why doesn't the Objective-c runtime do this automatically when an object is finally dealloc'd?

Because pointers are passed by value and not reference. All dealloc gets is a local copy of the pointer; any changes it makes are discarded. Same goes for C's free and C++'s delete.

How would the runtime be able to track down all such references?
MyClass* a = [MyClass new];
MyClass* aCopy = a;
[a release];
a = nil; // Tidy up
[aCopy crashNowPlease];
Sometimes you can catch this sort of thing with Build & Analyze.
Also, you will be able to use zeroing weak references in the future (or, Mike Ash created such a facility).

In objective-C, the objects are always accessed as pointer.
Setting an object to nil simply change the pointer value, not the object value.
In your method, you have only access to the object's value, not to the pointer pointing to it!
As #David Dunham says, you can have more than one pointer to an object, so how would the compiler knows?
And more than that, to make things easier, imagine the following code :
int a;
int* aPtr = &a;
If you change a value, you can access the changed value via *aPtr right? But you can change a value as long as you want, it won't change aPtr value, as it is not the same variable!
Thus, even if you only have one pointer to your object, if you modify the object's value, you pointer will still point to the same address value!

What you are describing is called a zeroing weak reference. This feature is available in OS X 10.7's Automatic Reference Counting (ARC) runtime. Prior to 10.7, you can use Mike Ash's zeroing weak reference implementation.
Without explicit runtime support (and some small but unavoidable overhead), standard C-style pointers (id in Objective-C is a pointer to a structure) are just a memory address (an integer) and not tracked by the runtime. There's nothing stopping you from making copies of this value elsewhere in memory or from storing the value in an integer of the appropriate size and casting to an id later on (of course if you do any of this, you kill a baby seal). Thus, when an object is dealloc'd there's no way to know where (or how many) references there are to that object.

Related

How does ARC work in the following code snippet in ios?

Let's say I have a method that returns an object pointer
-(MyObj *) returnMyObj {
MyObj *obj = [MyObj alloc] init];
return obj;
}
If I call this function without assigning the pointer like this
Scenario 1
[self returnMyObj];
and if I call this function with assignment to a pointer like this
Scenario 2
MyObj* obj = [self returnMyObj];
Compiler can release the object at the end of the returnMyObj method call in the Scenario 1 but it cant do the same in Scenario 2.How does ARC decide if it needs to retain the created object at the end of method invocation or not in both cases?
Here is what the ARC article in the documentation has to say:
To make sure that instances don’t disappear while they are still needed, ARC tracks how many properties, constants, and variables are currently referring to each class instance. ARC will not deallocate an instance as long as at least one active reference to that instance still exists.
To make this possible, whenever you assign a class instance to a property, constant, or variable, that property, constant, or variable makes a strong reference to the instance. The reference is called a “strong” reference because it keeps a firm hold on that instance, and does not allow it to be deallocated for as long as that strong reference remains.
ARC decides which objects will be kept in memory and which will be deallocated by counting the strong references to the objects.
In your second scenario you are creating a strong reference to the MyObj instance and ARC will not deallocate it while the object is in use. In this case it will be deallocated when the method that uses this object finishes.
The optimizer may absolutely release the object in scenario 2 at the end of the statement if obj is not referenced later in the block.
The whole point is that the optimizer can see when the pointer is referenced, and may release it as soon as the last reference is completed. obj does not have precise lifetime semantics, so it only extends the life of the object until the last time obj is referenced, not when obj goes out of scope.
In scenario 1, the reference is not assigned to any variable, so it clearly has no later references, and may be immediately released. That said, it may not immediately release the object, since returnMyObj does not transfer ownership to the caller (due to its name). So the object may not actually be released until the autorelease pool drains.

ARC behavior on assigned local variable to an instance variable

Question 1
Supposed I have this code:
MyClass * __strong foo = [MyClass new];
MyClass * __strong bar = foo;
// foo = nil; // by ARC?
In reference to this answer, does ARC automatically nil out foo on line 3 since bar already acquired the reference?
Question 2
//ECGService.m
#property (strong) MuttableArray *rriData;
(MuttableArray *)getRriData {
return _rriData;
}
//AlgorithmTest.m
// according to Apple docs, local variable are marked __strong by default
MuttableArray *rriData = [self.ecgService getRriData];
for(NSNumber *rri in rriData) {
// use rri!
}
// rriData = nil;
Should I nil out the local variable rriData after using it?
And, does the __strong attribute must only be applied to only one instance of an object?
Answer 1.
In principle, ARC doesn't “nil out” foo until it goes out of scope. When it goes out of scope, ARC releases its reference. It doesn't have to actually set foo to nil, but the effect is exactly as if ARC does set it to nil.
In practice, ARC is usually allowed to release the reference held by foo immediately after the last use of the foo variable, which may be long before it goes out of scope. In your example, if the only place where you use foo in the function is in the assignment to bar, then ARC is allowed to release foo's reference immediately after that assignment. Note that generally there's no way for you to know about this early release because you don't use foo again! Note also that bar will still reference the object unless bar is also not used later in the function.
There are some special attributes that can prevent ARC from performing this early release, called objc_precise_lifetime and objc_returns_inner_pointer but usually applied through the macros NS_VALID_UNTIL_END_OF_SCOPE and NS_RETURNS_INNER_POINTER. These are advanced features that you probably won't have to worry about any time soon, but if you want to see some examples of NS_RETURNS_INNER_POINTER, take a look at NSString.h.
Answer 2.
You don't need to “nil out” rriData. ARC will release its reference when it goes out of scope (or sooner—see answer 1).
You don't need to say __strong usually, because it's the default, and it's what you want usually. It is normal to have multiple strong references to an object. You use __weak explicitly when you need to prevent a retain cycle. There are many explanations of retain cycles on the web and on stack overflow, so if you need to learn about them, please visit your favorite search engine.
In reference to this answer, does ARC automatically nil out foo on line 3 since bar already acquired the reference?
No. ARC stands for Automatic Reference Counting. Obviously counting does not stop with 1.
It is the strength of ARC that every reference is handled independently of other references. A strong foo retains the referred object as long as it points to. It does not matter, whether other reference variables points to the same object. Track every reference isolated.
There is only one case that let ARC change the value of a reference variable: If it is marked with weak and there is no other strong reference to the object. This is the intended behavior.
As a result of optimization it is possible that retains and releases are omitted or different local variables in source code are put together. This is transparent for you.
Should I nil out the local variable rriData after using it?
You should not care about this. A strong reference variable automatically retains an object, whose reference is stored in the reference variable. And it automatically releases the object, if it does not point any longer to it. This includes releases on
a new value is assigned to the reference variable
nil is assigned to the reference variable
the reference variable loses it extent (lifetime).
Because of the last fact, there will be an automatically generated release, when rriData loses it extent. There is no reason to nil it out in advance.
Question 1. No, you simply end up with two references to the MyClass instance. Nothing gets nilled out.
Question 2. No, you don't need to nil out anything. ARC manages memory for you. That's the point. You also never need to say __strong. It is the default.

Weak and strong property implementation

I want to better understand strong and weak pointers implementation, and i figure out assumptions, about how their setter methods would look like (correct me if i wrong please).
First, strong pointer, look like:
- (void)setObj:(NSObject*)Obj // Setting Strong Obj
{
//First, check either we trying to set old value again
if (_Obj == Obj)
{
return;
}
NSObject* oldObj = _Obj;
_Obj = [Obj retain];
[oldObj release];
// Set pointer to old "chunk" of memory, containing old value,
// assign new value to backed instance variable and release
// old value
}
That is my assumption of construction, that strong setter may look like. So, my first question is - am i correct in my assumption?
Second, weak reference. I guess, it should look similar, but exclude retain.
- (void)setObj:(NSObject*)Obj // Setting Weak Obj
{
if (_Obj == Obj)
{
return;
}
NSObject* oldObj = _Obj;
_Obj = Obj; // setting value without incrementing reference count
[oldObj release];
}
Is that correctly assumption, about how weak reference work?
Ok, one more question. Consider a situation like that (in Manual Memory Management):
- (void)testFunc
{
strongObj = val; // Retain count about >= 2
weakObj = val; // Retain count about >=1
}
// Now strongObj lives in memory with value of val, with retain count >=1
// weakObj is destroyed, since after end of a scope (function body) it retain count decreased by 1
So, actually i want to know, whether retain count decremented each time, when method that own variable finishes?
I know that question is familiar to many developers, but, i want clarification in that cases. Thanks.
Your strong implementation is correct.
The weak one is wrong. You are not allowed to release the value if you have not previously retained it. You would just set the new value without issueing memory management calls here.
Then again, that wouldn't really be weak, but assign. The special thing about weak is that the reference is zeroed out of the referenced object is deallocated.
For the first and second Q I refer to #rmaddy's comment and Christian's answer.
So, actually i want to know, whether retain count decremented each time, when method that own variable finishes?
First I want to be more precise: When you say "when method that own a variable finishes" you probably mean "when a local strong reference variable of automatic storage class loses its extent". This is not exactly the same. But it is what you likely wanted to say. ("A usual local var.")
In this case it is correct that the referred object is released.
But things are more difficult behind the scenes. I. e.: What happens if the local var (more precise again: the referred object) is returned? What happens in this case, if the method is ownership transferring or not?
The basic problem is that an automatic reference counting has to take edge cases formally into account, even in "usual" code things couldn't break. A human developer can say: "Oh, there is a very special situation the code can break, but I know that this never happens." A compiler cannot. So ARC typically creates very much memory handling calls. Fortunately many of them are optimized away.
If you want to have a deep view into what is done in which situation, you have two good approaches:
Read clang's documenation, which is more precise than Apple's by far, but it is more complicated.
Create a class in a separate file that implements the methods for manual reference counting (-retain, -release, …) and log the execution. Then compile it with manual reference counting, which is possible through compiler flags. Use that class in ARC code. You will see, what ARC does. (You should not rely on the results, because they are subject of optimization and the strategy can change in the future. But it is a good tool to understand, how ARC works.)
It may be helpful to think about strong and weak references in terms of balloons.
A balloon will not fly away as long as at least one person is holding on to a string attached to it. The number of people holding strings is the retain count. When no one is holding on to a string, the ballon will fly away (dealloc). Many people can have strings to that same balloon. You can get/set properties and call methods on the referenced object with both strong and weak references.
A strong reference is like holding on to a string to that balloon. As long as you are holding on to a string attached to the balloon, it will not fly away.
A weak reference is like looking at the balloon. You can see it, access it's properties, call it's methods, but you have no string to that balloon. If everyone holding onto the string lets go, the balloon flies away, and you cannot access it anymore.

Does an object has pointers to it's pointers?

In ARC, when an object is released, the pointer is set to nil.
How does the object tell all those points that it's about to be released?
Does this work for strong pointers or all types of pointers?
Based on some quick reading of what ARC required be added to the Objective-C runtime, the weak reference itself is registered with the runtime. There are a bunch of calls for setting up a weak connection, tearing it down and reassigning it. The compiler acts to decide what sort of assignment to do, much as it also has a role in automatically retaining and releasing. Per the linked document:
The runtime tracks __weak objects which holds non-null values. It is
undefined behavior to direct modify a __weak object which is being
tracked by the runtime except through an objc_storeWeak,
objc_destroyWeak, or objc_moveWeak call.
From that I'd conclude that the runtime maintains a collection of every weak pointer that currently points to a given object. When that object is deallocated it zeros out the pointers.
So there is a list, per object, that points to the relevant pointers to create a two-directional connection. How and where that's stored isn't explicit — it could be via the existing object association mechanisms, it could be a global dictionary, it could be just about anything.
In ARC (or MRC), a pointer is NOT set to nil when an object is released. In ARC, a weak object reference is set to nil when an object is deallocated, not when it is released. There is a big difference here.

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.