Why maintaining retain count is not required in ARC enabled project - ios

Retain counts are the way in which memory is managed in Objective-C. When you create an object, it has a retain count of 1. When you send an object a retain message, its retain count is incremented by 1, which we know that ARC does it automatically but how it does what is the technique it use??
And I still wonder if memory management is done automatically then why sometimes we get bad access error for objects allocations or retrieval.
I have already gone through this link:- https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html

I think ARC (done by the compiler at compilation time, by inserting retain/release command where 'necessary') relies on the scope of variable, the block of code where they are defined (i.e. initialized) and if its value is stored in another variable whose scope is broader than the initial variable's scope.
That's why you have to declare more precisely the type of variable access and storage: to inform the compiler your intentions with a variable.
But I think too that ARC can't see further than the current file. ARC is more tricky with global variables and inter-files dependencies.
So, Apple a more complex variable's declaration grammar to replace a very simple (IMO) retain/release pattern. So developers don't have to worry about memory management.
That enable Apple ecosystem to be accessible to a lot more developers used to managed languages (like web developers) to develop for iOS.
I think it is a mistake to make developers believe you can develop efficiently without having to understand such a fundamental concept in IT as memory management.
But more developers for iOS means more programs developed and a more stable ecosystem in term of activity, so more revenues for Apple :-)

You would be better off reading the ARC docs: https://developer.apple.com/library/ios/releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html
ARC will manage the memory for you, but it cannot stop you from writing programming errors such as only holding weak references to an object.

Related

Can a garbage collected language compile to a non-garbage collected one without including a garbage collector in the runtime?

As I understand it, when a managed language (like Haxe) can and wants to compiles to a non-managed language (like C++), it includes some form of garbage collector in the runtime.
I was wondering if it would be possible to completely abstract away memory management in the intermediate representation / abstract syntax tree, so that a garbage collector would not be needed and the default behavior (stack allocations live until end of scope and heap allocations live until freed) could be used?
Thank you!
If I understood you correctly, you're asking whether it's possible to take a garbage collected language and compile it to an equivalent program in a non-garbage collected language without introducing memory errors or leaks, just by adding frees in the right places (i.e. no reference counting or otherwise keeping track of references or implementing a garbage collection algorithm in anyway or doing anything else at run time that could be considered garbage collection).
No, that is not possible. To do something like this, you'd have to be able to statically answer the question "What's the point in the program, after which a given object is no longer referenced", which is a non-trivial semantic property and thus undecidable per Rice's theorem.
You could define a sufficiently restricted subset of the language (something like "only one live variable may hold a strong reference to an object at a time and anything else must use weak references"), but programming in that subset would be so different from programming in the original language¹ that there wouldn't be much of a point in doing that.
¹ And perhaps more importantly: it would be highly unlikely that existing code would conform to that subset. So if there's a compiler that can compile my code to efficient GC-free native code, but only if I completely re-write my code to fit an awkward subset of the language, why wouldn't I just re-write the project in Rust instead? Especially since interop with libraries that aren't written in the subset would probably be infeasible as well.

Do we lose objc_retain()/objc_release() optimization for ARC if we override retain/release methods?

Edited: Some of you think ASDealloc2MainObject from AsyncDisplayKit doesn't really override retain/release. I modified the source code behind ASDealloc2MainObject (line 405-428 of _AS-objc-internal.h), added a printf() inside the overridden release method and did a few test runs on my iPhone. The log was printed as expected. My test code (including a new class that inherits from ASDealloc2MainObject) was compiled with ARC enabled.
I used to believe that overriding retain/release methods cannot be done under ARC. Turns out I was wrong. Such a technique involves a base class compiled under MRC and its subclasses compiled under ARC.
One good example is the Facebook AsyncDisplayKit. Lots of classes from the Facebook AsyncDisplayKit framework inherit from a base class called ASDealloc2MainObject. ASDealloc2MainObject is a class that compiles under MRC and overrides NSObject's retain/release methods. In the meantime, subclasses of ASDealloc2MainObject compiles and runs under ARC.
I have two questions:
Quite a few blog posts on the internet say that when ARC is inserting memory management code during compile time, it will insert low level C functions such as objc_retain() and objc_release() rather than their Obj-C equivalents [NSOject retain] and [NSObject release]. ARC does this because low level C functions could provide extra optimization, such as eliminating costly Obj-C message sending and canceling adjacent autorelease and retain calls. My question here is, if we use the MRC/ARC overriding technique, do we lose such optimization?
My second question is in some way related to my first question. What's the runtime behavior of objc_retain()/objc_release() if the target object's base class has overridden its retain/release methods? My guess is that these C functions are able to figure out the situation here. Instead of performing their regular optimizations (such as eliminating sending retain/release messages), they would in fact revert to the old way and actually sends out retain/release messages.
Quoting the documentation:
You would implement [the retain] method only if you were defining your own reference-counting scheme. Such implementations must return self and should not invoke the inherited method by sending a retain message to super.
Are you implementing your own memory management system? No? Then do not override retain or release.
Apple also advises against using reference counting for all Objective-C code. You are supposed to be using ARC.
ASDealloc2MainObject does not override retain or release. Old versions did but FaceBook realised that was a terrible idea and have updated their code to use ARC.
As for how exactly ARC behaves, the answer is "it depends". There are many different ways it can behave. Go read the compiler source code if you really want to know how it works.
That blog post you linked to is ancient and should not be trusted at all. Apple makes breaking changes to the compiler every 12 months and that means they've done so 3 times since the blog post was written. Since memory management is a performance bottleneck, that's where they make the most changes each year.
Sending a "retain" or "release" message to an object is outrageously slow. ARC and the Objective-C runtime both try to avoid sending messages as much as possible. One of the reasons the Swift language was created was to eliminate sending messages altogether. objc_retain() and objc_release() exist to avoid sending retain and release to an object. There might be situations where they do so but you can't rely on it.
I'd suggest that you write some code and try it. I'd expect that retain/release are not actually called from ARC code, because it uses (faster) function calls. So your overrides won't work when called from ARC. They probably work when called from non-ARC code.
That's to find out what happens. In practice, overriding retain/release in mixed ARC/non-ARC code will probably just get you into trouble.

non ARC classes in an ARC compliant project?

I am working on an iPhone app which does some video processing, I had to include to classes that are not ARC compliant ( dealloc , releasing stuff ). So I manually went and made them arc compliant.
Later on I discovered the compiler flag for any class that can make it non ARC in an ARC project -fno-objc-arc.
My question is, if I do flag those classes with the compiler flag, what are the reprecussions of this? performance hit? is it a good idea? my app iOS 5.0 and up. I couldn't find any resources that talk about pros and cons of doing this.
You ask:
If I do flag those classes with the compiler flag, what are the repercussions of this?
The only thing I believe you need to worry about is to make sure that the non-ARC library follows Cocoa naming conventions associated with memory management (e.g. only return objects with +1 retainCount if the name begins with alloc, new, copy, or mutableCopy). Otherwise your ARC won't be able properly manage the resulting object. Most well written classes will conform to this pattern, so you should be perfectly ok using the fno-objc-arc flag, but it depends entirely upon the class in question.
[Is there a] performance hit?
There are no practical performance issues.
[Is] it a good idea?
All things being equal, I generally like to convert the code to ARC. A couple of situations where I might refrain from converting:
It is a library for which there is active development, and if I create my own personal ARC fork, I'll lose out on the future revisions of the library.
The library is incredibly complex and/or has constructs that are not easily converted to ARC.
Bottom line, if I can convert to ARC, I will. Usually in this process, I'll do the necessary testing to make sure I'm comfortable with the library, that there are no leaks, etc., so it's a productive (if annoying) process to go through. We're all responsible for the code we include in our projects and I don't think one should ever integrate code without going through some due diligence that is a natural by-product of an ARC-conversion and testing process.
If I convert to ARC, I offer to contribute the conversion back to the original author (e.g. via a GitHub "pull request" or whatever mechanism the author is open to) so it can be integrated into the code base.
At first glance, there are no performance issues with using or disusing ARC. ARC is basically normal reference counting, it's just not the programmer who inserts the release calls, but the compiler.

When should I enable “reference counting extension” in MonoTouch build settings?

In what circumstances should I be using this feature?
How exactly mature is it?
What are the pros and cons?
What problem does it solve?
Is it specific to MonoTouch, Mono GC, or reference counting in ObjC?
Here are some quick, high-level (and out or order) answers to your questions...
Is it specific to MonoTouch, Mono GC, or reference counting in ObjC?
It allows sgen, the mono garbage collector, to work more closely with Objective-C reference counting. That awareness is not needed for Mono (or Mono for Android) so it's specific to MonoTouch.
How exactly mature is it?
As the UI says: Experimental preview. So while we know it works it has not yet seen a wide usage inside applications (compared to the default GC). It's more a direction than a destination (i.e. it will likely evolve).
You're more than welcome to test it, use it (if it proves useful in your situation) and report your findings/experiences with it. However it's not fully supported, e.g. you might hit a bug that we can't immediately fix or workaround (beside asking you to go back to the default settings).
What problem does it solve?
The coexistence of a garbage collector and the reference counting of Objective-C is very complex subject. MonoTouch tries it best to hide (most of) complexity of this to the developers.
Most of this is done inside the runtime (e.g. by using the backing fields). This extension to sgen is meant to have the GC itself (not only the runtime) aware of the needs for reference counting.
What are the pros and cons?
PRO: It saves memory as the linker can remove many of the backing fields that would be otherwise required to ensure we keep a reference to the managed objects. Without those (references to) backing fields the GC would normally collect the instances (while they are still needed by unmanaged code).
CON: We need more feedback, more comparison data (e.g. performance).

pointers in structs a memory leak?

I couldn't find any mention of this online... wouldn't putting a pointer in a struct be a bad thing? (at least in the modern object oriented programing) The programmer would inevitably creating a memory leak correct? (unless they, every time they use it, they disassociate the memory every time)
Assuming that the above is correct... is it considered a bad practice to use pointers in structs? - specifically accounting potential memory leaks?
Assuming this is about C++, putting a dumb pointer into a struct is indeed dangerous if this pointer refers to an object (or an array of objects) that is owned by the struct's instance (that is, the instance is responsible for the proper deletion of the object).
Copying an instance of the struct means copying all of its members. After that, you end up with several instances of that struct having pointers to the same object. When all of these instances are about to be deleted, you would have to delete the object referred to by the pointer. However, if one of them is about to be deleted, it is often hard to tell if other instances are still around somewhere.
A way out of this would be reference-counting, done by clever implementing constructors, destructors, and assignment. Fortunately you don't need to implement this yourself, since it's already been done in so-called smart pointer. Either your standard library ships TR1's std::tr1::shared_ptr or it already comes with C++11's std::shared_ptr or you can download the boost libraries and use their boost::shared_ptr.

Resources