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.
Related
As far as I know, when I dereference a dead weak reference in Objective-C, I get a nil value as the result. I'm wondering if there is any way to actually tell if there was a weak value assigned to the variable once it goes away as opposed to simply having a value of nil (for instance if the reference was never assigned).
Is there perhaps a lower-level runtime function that I can use?
I've taken to using a BOOL to record when the reference is assigned, but this feels ugly to me.
As Rob said, you can't do it directly. But you can do so indirectly.
By using associated objects, you can associate a subclass of NSObject with the object being weakly referenced. In that subclass, override dealloc to notify something that the weakly referenced object is being deallocated.
As long as you make absolutely sure that the weakly referenced object's associated reference to your NSObject subclass is the only strong reference to your subclass's instance, then you've effectively created a means of receiving a notification of when the weakly referenced object is deallocated.
Yes, it is fragile. One additional strong reference to that subclass's instances and the whole thing stops working.
No, there is no way to tell if a weak reference has been set to nil because its referent has been deallocated.
The weak reference is set to nil by weak_clear_no_lock in objc-weak.mm.
Class __weak *variable = preExistingObjectWithStrongReference;
If the above code is called, and a object with a strong reference is then pointed to by a new pointer 'variable', and the __weak attribute is assigned to it...
Does that simply mean that the reference count remains untouched? Or does it mean that the original object is now no longer strong referenced?
__weak specifies a reference that does not keep the referenced object alive. A weak reference is set to nil when there are no strong
references to the object.
This means that you can use variable safely as long as there's any other strong reference to the same object. In a certain sense you can think of it as the 'reference count remains untouched' as you said.
Neither; this means that the compiler will keep the reference alive as long as someone else points to it strongly. If there are no more strong references, and all of the objects that refer to your weak pointer are gone, the object is deallocated. Generally you only use weak on objects that you do not own. If you do own them (i.e it is something that "belongs" the the class) then strong is a better choice. A weak is essentially an unretained property, except the when the object is deallocated the weak pointer is automatically set to nil.
When you instantiate an object inside a method, when that method is called the object will be allocated memory but what object will hold reference to this object or will it be automatically be deallocated when the method ends. Thanks.
In OS X and iOS 5+, Objective-C uses Automatic Reference Counting. In this case, the object is freed when it goes out of scope, just like you'd expect.
Before that, you needed to explicitly retain and release objects. Here's a useful article from 2010 on this topic.
Objective-C in retain count mode (not using garbage collection) is a
simple idea. When you explicitly allocate an object it gets a retain
count of 1 and when you call release or autorelease on an object it's
retain count gets decremented and then the object will be collected.
It is the only mode available on iOS Devices and has been in use on
Mac OS X since the beginning of the OS.
Short answer, if you are using ARC (Automatic Retain Count) or if the object is autorelease it will be sent a release message when appropriate.
If you are manually managing the memory, you have to manually send a release method to those object whenever they are returned by either new, alloc, retain, copy or mutableCopy, otherwise the object will leak as you will be losing any reference to it when the stack gets teared down.
If your application is ARC then it will be dealloc'd after it goes out of scope. If the object is a property of a class then it will be cleaned up by different rules depending on whether it is defined as strong or weak. Strong means that the object will not be cleaned up as long as the object that owns it points to it (so as long as the object that owns it exists then it will not be cleaned up). Weak means that the object will not be cleaned up as long as another object points to it.
I am using ARC. I have a method that runs at the end of a game I have written which should clear up memory. There are a series of objects in an NSMutableArray, which i remove using removeObject:. I then set these objects to nil. However, using NSLog on these objects shows that they still exist. Why does setting them to nil not remove them from memory?
In ARC (automatic reference counting), setting a reference to an object to nil means two different things depending on the kind of reference you are nil-ing:
If it is a strong reference, then nil-ing it means decreasing the reference count of the referenced object;
if it is a weak reference, nil-ing it does nothing.
Thus, nil-ing can lead to different outcomes. Specifically, it is only when the reference count goes to zero that the object is deallocated. This would correspond to a case where no other object in the system is owning the first one (which means holding a strong reference to it).
So, in your case there could be either some other objects keeping a strong reference to the objects you try to nil; or, you might be nil-ing a weak reference. If you show some code, it may become clearer.
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.