How can I check if my program is running in an ARC (Automatic Reference Counting) device?
I can use this code:
#if ! __has_feature(objc_arc)
# define FMDBRelease(__v) ([__v release]);
#else
# define FMDBRelease(__v)
#endif
But this work in compile time. A easy code for this is:
if ([object respondsToSelector:#selector(release)]) {
[object release];
}
But not work. I am not finding it in any place. There are a solution for this?
ARC is a compile time technology, thus the #if __has_feature(objc_arc) way is the correct way of doing this.
You can't. ARC is a compile-time tool. It has no real presence at runtime, except for the insertion of calls that allow for tail-call optimization.
Related
I'm working on a library and I would like to support both memory management approaches (ARC and MRR) in one codebase.
I don't want to force users to use special flags for my code (-fobjc-arc).
I know about the preprocessor test: #if __has_feature(objc_arc), but what is the best practice to use that to cover the all differences?
Does anyone have any experience with that to make it clean and easy to work with?
The preferable way would be to use some macros for translations between ARC and non-ARC, which I can use in my code.
=========
My problem was solved by the accepted answer, but as a tip for others, I found a blog post by John Blanco giving the best set of examples for how to handle my problem.
Refer the code of MBProgressHUD in github. I think, that's what you want.
#if __has_feature(objc_arc)
#define MB_AUTORELEASE(exp) exp
#define MB_RELEASE(exp) exp
#define MB_RETAIN(exp) exp
#else
#define MB_AUTORELEASE(exp) [exp autorelease]
#define MB_RELEASE(exp) [exp release]
#define MB_RETAIN(exp) [exp retain]
#endif
This is how they are using these macros
self.indicator = MB_AUTORELEASE([[MBRoundProgressView alloc] init]);
Either use ARC and instruct people who will use the code to set compilation flags per file (-fobjc-arc), and force them to do so by adding this to the header:
#if !__has_feature(objc_arc)
#error ARC must be enabled!
#endif
Or build as lib/framework with ARC enabled. Wrapping memory management code in preprocessor directives is a terrible idea.
One way to support both ARC and Non-ARC code is to go to the Target, Build Phases, and to the Compile Sources section.
From there you should see all your .m files. You can then add to any file -fno-objc-arc under the Compiler Flags to tell the compiler to ignore ARC.
Yeah, don't do this. You'll end up having to test your code fully twice for every change. And debugging everything twice. It isn't worth the effort.
You really really want to write your code purely ARC or purely non-ARC.
There are very few constructs that can appear in a header file that won't work in one or the other.
Coming from the world of managed memory, wondering what would be the proper way to clean up objects when using ARC.
For example: if declaring an instance variable in C#, .NET will allow the GC to pick it up once it leaves scope (method/loop body, etc)
What's the proper way to clean-up in Objective-C? Just set the reference/pointer to nil or call dealloc or will ARC detect that no external references are pointing to the instance once execution leaves scope and do the job for you?
ARC means "Automatic Reference Counting" and is just a way to let the compiler add the calls to retain/release/autorelease for you. It's not the same as GC but in most cases, you can consider that objects lifetime is automatically managed for you, like in GC.
If you want more information, you should read LLVM document on ARC
Last note: never call dealloc yourself. dealloc is the object's finalizer which is called once the ObjC runtime determines that the object reference count has reached 0. This method is only meant to be overriden by subclasses. In ARC mode, you generally don't need to do that, except if your object references non-object ivars that need to be finalized once the object itself is finalized.
will ARC detect that no external references are pointing to the
instance once execution leaves scope and do the job for you
Basically, yes, that's exactly what ARC will do. You don't need to clean up objects when you're using ARC; in fact, you can't (it stops you from trying to perform manual memory management).
You might want to consult the relevant discussion in my book:
http://www.apeth.com/iOSBook/ch12.html#_memory_management
It explains what's really happening behind the scenes (how memory is actually managed) and then goes on to describe how ARC shields you from most of it.
Note that (as I explain in the URL referenced above) it mostly isn't done by anything like garbage collection: it's done by inserting invisible explicit memory management throughout your code.
Well, in the past, iOS programmers were responsible for telling the system when they were done using an object that they allocated by sending the object a release message. That was done in accordance with a memory management system known as manual reference counting. As of Xcode 4.2, programmers no longer have to worry about this and can rely on the system to take care of releasing memory as necessary. This is done through a mechanism known as Automatic Reference Counting, or ARC for short. ARC is enabled by default when you compile new applications using Xcode 4.2 or later.
You can also disable ARC, in your Xcode interface, go to your main project (not main.h) your actual Xcode project, and select it, you should see a window in Xcode that displays the settings for your project, there will be one that says 'Objective-C Automatic Reference Counting' and it will be set to 'Yes', deactivate it (to 'No') and you shouldn't worry about the ARC, if you come from the world of data management and memory as you said, but keep in mind that it would be easier to you to keep updated to the iOS new features system, that are easier to the programmer to program, it just makes our life easier.
And now, the 'proper way to clean-up in Xcode' with ARC is with 'alloc' and 'init'.
With ARC in Xcode you do not need to worry for 'cleaning' that's the job of Xcode now, you just need to:
1) Create a variable.
2) Allocate.
3) Initialize.
That's it.
An example here:
int main (int argc, char * argv[])
{
#autoreleasepool {
Variable *myVariable;
// Create an instance of a Variable and initialize it
myVariable = [Variable alloc];
myVariable = [myVariable init];
// Set variable to 4/20
[myVariable setNumerator: 4];
[myVariable setDenominator: 20];
// Display the variable using the print method
NSLog (#"The value of myVariable is:");
[myVariable print];
}
return 0;
}
Just allocate and then initialize, yo do not need to do any thing else.
Keep in mind getters and setters.
When compiling an older project in Xcode 4.5, there is a warning:
'__bridge' casts have no effect when not using ARC
What's the proper way to get rid of this warning, such that the code works well in both ARC and non-ARC projects?
Any individual source file has to either be compiled with ARC or not compiled with ARC. You should just make up your mind which it is and always use that method for the particular source file. Provided you stick to the memory management naming conventions, you can mix ARC and non ARC source files in the same project.
The reason I say the above, is that if you have code that was written for ARC and you compile it without ARC, there will be memory leaks and premature deallocations all over the place thanks to the fact that all of the retains, releases and autoreleases are missing.
With a few #define's it is quite possible to write source files which compile correctly for more than one of MRC, ARC & GC.
Xcode does not allow you to enable both ARC & GC, knowing that we can write:
#if defined(__OBJC_GC__)
# define USING_GC 1
#else
# define USING_GC 0
#endif
#if __has_feature(objc_arc)
# define USING_ARC 1
#else
# define USING_ARC 0
#endif
#if USING_ARC || USING_GC
# define USING_MRC 0
#else
# define USING_MRC 1
#endif
which will define just one of USING_GC, USING_MRC and USING_ARC as 1 and the other two as 0. You can put that in your projects prefix header (.pch).
You can use these defines directly in your code to include/exclude things like bridge casts; or better to define macros for memory calls, casting, etc. which expand to the appropriate code based on the memory model in use.
HTH
Simply turn on ARC for that file:
-fobjc-arc
(Go to Build Phases > Compile Sources > Compiler Flags)
I'm working on some Objective-C code I expect to spin off into a library or at least share with some other people. It requires ARC to use, and if ARC is not enabled, it will leak memory.
What is the correct way to make the code fail to compile if ARC is turned off?
You can check for ARC at compile time with
#if __has_feature(objc_arc)
I think a cleaner approach would be to compile the library as a static library. As ARC will incorporate the release calls according to the rules into the compiled library, it doesnt matter from that point on, if the project it is added to is ARC or MRC — so no hassle for the library user.
Is there a #pragma (or otherwise some construct) to explicitly enable automatic reference counting (ARC) in an Objective-C (or Objective-C++) source file? Even better if the source file can cause compilation to fail if ARC is not enabled.
I'm starting to have a number of ARC-only source files that can be potentially shared with other projects. Most of these contain category methods to extend built-in classes. I just don't want to accidentally include these in a non-ARC project and starts leaking out memory.
Thanks in advance!
As far as I can tell there is no way to explicitly enable or disable ARC.
However it is possible to detect if it is enabled. Simply add the following snippet to any file that requires ARC.
#ifndef __has_feature
#define __has_feature(x) 0 /* for non-clang compilers */
#endif
#if !__has_feature(objc_arc)
#error ARC must be enabled!
#endif
More info:
http://clang.llvm.org/docs/AutomaticReferenceCounting.html
http://clang.llvm.org/docs/LanguageExtensions.html#__has_feature_extension