Why is an object not automatically set to nil when its reference count becomes 0? - ios

In a non ARC Objective C environment, I understand why we have to release an object: to free the memory allocated for it; I understand why we have to set it to nil afterwards (if we are sure nothing else needs the instance / nothing else still has a hold on the object): to avoid dangling pointers.
However my question is, if all objects release their hold on an object, "carInstance" for example, resulting in its reference count going down to 0, why oh why does that Not automatically make it nil?
If reference count is now 0, is the object still usable in any way? Or is this just one of those things we have to do just because that's how not having garbage collection works (can't be, there must be a reason)

The simple answer is that the manual memory management model that was used pre-ARC is lightweight and simple. The behavior you are wishing for is the behavior you get with weak pointers under ARC; and it requires extra work by the OS, to track weak pointers and nil them out when the object is reclaimed. It's doable, clearly, but the cost of implementing it, as well as the computational overhead, wasn't deemed worthwhile until Apple was already rolling out the extra work of implementing ARC.
After an object is deallocated, the dangling pointer is worse than useless: it is downright dangerous. Referencing it while it points to unallocated memory produces an exception; referencing it after it is randomly reassigned to another object or some other memory allocation will typically produce an 'object does not respond to selector' error.

Related

Does dart reuse memory for previously used instances?

It is hard to find a good heading for this, but i think my problem comes clear if i post a small code snipped:
SomeObject instance = SomeObject(importantParameter);
// -> "instance" is now a reference to the instance somewhere in RAM
instance = SomeObject(anotherImportantParameter);
// -> "instance" is now a reference to a different instance somewhere in RAM
My question is now, is the used RAM that was allocated at the first construction reused at the second construction? Or is the RAM of the first instance marked as unused for the garbage collector and the second construction is done with a completely new instance with a different portion of RAM?
If the first is true, what with this:
while(true) {
final SomeObject instance = SomeObject(importantParameter);
}
Will then, each time the while is repeated, the RAM be reused?
It's unspecified. The answer is a resounding "maybe".
The language specification never says what happens to unreachable objects, since it's unobservable to the program. (That's what being unreachable means).
In practice, the native Dart implementation uses a generational garbage collector.
The default behavior would be to allocate a new object in "new-space" and overwrite the reference to the previous object. That makes the previous object unreachable (as long as you haven't store other references to it), and it can therefore be garbage collected. If you really go through objects quickly, that will be cheap, since the unreachable object is completely ignored on the next new-space garbage collection.
Allocating a lot of short-lived objects still has an overhead since it causes new-space GC to happen more often, even if the individual objects don't themselves cost anything.
There is also a number of optimization that may change this behavior.
If your object is sufficiently simple and the compiler can see that no reference to it ever escapes, or is used in an identical check, or ... any other number of relevant restrictions, then it might "allocation sink" the object. That means it never actually allocates the object, it just stores the contents somewhere, perhaps even on the stack, and it also inlines the methods so they refer to the data directly instead of going through a this pointer.
In that case, your code may actually reuse the memory of the previous object, because the compiler recognizes that it can.
Do not try to predict whether an optimization like this happens. The requirements can change at any time. Just write code that is correct and not unnecessarily complex, then the compiler will do its best to optimize in all the ways that it can.

Can we use deinitialized variables in code, or are they pretty much useless because they are deallocated right after?

Im a little confused on the topic of deallocation when comparing it to deinitaizlization. Doesn't deallocation happen the moment after a variable is deinitialized.....My main point here is, Could we use/manipulate deinitialized variables somehow? or they are pretty much useless because deallocation takes place right after...?
In Swift the deinit method is called as part of the deallocation process. Precisely when the memory allocated to an object is released you cannot know, but you can't access the object after it has been deinitalised.
Aside from it not making any sense to do so, it isn't possible to manipulate the object after deinit since the deallocation process is initiated by the removal of the last strong reference to the object. as there are no references how could you manipulate the object anyway. (I suppose you could use an unowned/unsafe reference to attempt to access the object but this would result in your app crashing)

Manually set nil to swift object to avoid retain cycle?

I've been profiling one of the apps written in swift lately and been very frustrated with ARC in general, coming from languages where mark-and-sweep GC is the norm.
Especially, UIViewControllers that are very complex with lots of dependencies to other class, I've been failing to get ARC working properly. But I know that simply setting retained objects to nil gets them deallocated without dabbling with ARC.
This is especially true for UIViewController where I can set nil to all retained objects in viewDidDisappear or the similar.
Is this kind of practice considered bad / harmful? Should I just try harder to get ARC working?
edit: By not working, I mostly mean to break Strong Reference Cycle, which becomes quite unwieldy when there are multiple hierarchies of dependencies.
edit: FYI, I'm aware that using weak / unowned in declaration / capture list breaks the retain cycle. I'm asking in cases where using those norms become unwieldy due to the complexity of an object or, rather, the retain cycle of an object.
I think you should take a look at your class structure - basically work out which classes should "own" certain properties (i.e. strong reference) and who just needs to be referencing them when they are available (i.e. weak references).
I think it is well worth thinking about this, as it will probably streamline your code. It will also give you an opportunity to really think about privilege - do all these other classes really need access to these objects etc.
The real problem with setting things to nil is that you have to be sure that you are catching all strong reference cycles and that, ultimately, you are not benefiting from ARC making your life easier.
Try deinit Method its wright way I guess
deinit{
person = nil
}

Is it possible to implement NSFastEnumeration when using weak references?

I have a collection which maintains weak references to its objects. I'd like it to conform to NSFastEnumeration, but the buffer provided by countByEnumeratingWithState:objects:count: uses unsafe_unretained references. That creates a gap during which a returned reference could become invalid but not zeroed.
That's fine in the general case -- if the collection stuffs its (currently valid but weakly-referenced) object into the buffer and returns it, then the caller will presumably create its own strong reference if needed. But that leaves two problems:
(1) I don't see any guarantee that the for(){} iteration construct itself creates a temporary strong reference to the object, so if the contents of the {x} block changes something outside the collection in a way that causes the object to be released, then it'll have a dangling reference.
(2) There's still a small gap while returning from countByEnumeratingWithState: during which activity on another thread could invalidate the reference. My collection isn't meant to be thread-safe, but it would be nice if it could at least safely store references to objects which could be referenced on another thread, as there's really no way to prevent that in any multi-threaded application.
You can't return a strong reference directly to the caller. The caller won't release it, and the fast enumeration protocol does not guarantee that you will get a chance to release it yourself when the caller is done.
Instead you can retain+autorelease the objects before you store them into the buffer. That would guarantee the objects stay alive while the caller uses them. It may hurt the "fast" part of fast enumeration, but you would still get the "convenient syntax" part. If you add a nil check after you read the weak variable then you can avoid storing nil pointers into the buffer.

ARC in iOS questions

~ Will ARC always release an object the line after the last strong pointer is removed? Or is it undetermined and at some unspecified point in the future it will be released? Similarly, assuming that you don't change anything with your program, will ARC always be the same each time you run and compile your program?
~ How do you deal with handing an object off to other classes? For example, suppose we are creating a Cake object in a Bakery class. This process would probably take a long time and involve many different methods, so it may be reasonable for us to put the cake in a strong property. Now suppose we want to hand this cake object off to a customer. The customer would also probably want to have a strong pointer to it. Is this ok? Having two classes with strong pointers to the same object? Or should we nil out the Bakery's pointer as soon as we hand off?
Your code should be structured so the answer to this doesn't matter - if you want to use an object, keep a pointer to it, don't rely on ARC side effects to keep it around :) And these side effects might change with different compilers.
Two strong pointers is absolutely fine. ARC will only release the object when both pointers are pointing to something else (or nothing!)
ARC will implement the proper retains and releases at compile time. It will not behave any different than if you put them in there yourself so it will always do the same compilation and to answer your question should always behave the same. But that said it does not mean that your object will always be released immediately after the pointer is removed. Because you never call dealloc directly in any form of objective C you are only telling it that there is no reference count and that it is safe to release. This usually means that it will be released right away though.
If you pass an object from one class to another and the receiving class has a strong property associated with it and the class that passes it off eventually nils its pointer it will still have a reference count of at least 1 and will be fine.
Ok, first this answer might helpt you also a little bit: ARC equivalent of autorelease?
Generally after the last strong variable is nilled, the object is released immediately. If you store it in a property, you can nil the property, assign it to something like __strong Foo *temp = self.bar; before you nil, and return that local __strong variable (although arc normally detects the return, and inferes the __strong byitself).
Some more details on that: Handling Pointer-to-Pointer Ownership Issues in ARC
DeanWombourne's answer is correct; but to add to (1).
In particular, the compiler may significantly re-order statements as a part of optimization. While method calls will always occur in the order written in code (because any method call may have side effects), any atomic expression may be re-ordered by the compiler as long as that re-order doesn't impact behavior. Same thing goes for local variable re-use, etc...
Thus, the ARC compiler will guarantee that a pointer is valid for as long as it is needed, no more. But there is no guarantee when the pointed to object might be released other than that it isn't going to happen beyond the scope of declaration. There is also no guarantee that object A is released before B simply because A is declared and last used before B.
IN other words, as long as you write your code without relying on side effects and race conditions, it should all just work.
Please keep you code proper as it has diffrent behaviour on diffrent complier.

Resources