#autoreleasepool with no foundation or corefoundation (libobjc only) - objective-c

NOTE: All references to libobjc are referring to Apple's runtime. I'll deal with the GNU runtime later.
I'm trying to get a handle on what exactly #autoreleasepool does at runtime so that I can use it in my foundation-less framework.
I've been able to hook into #(#), #[] and #{} to return instances of my number, array and dictionary classes — all derived from my root class and easier to hack as all the plumbing happens in objc — but #autoreleasepool seems to be handled differently by the compiler.
Rather than just injecting calls to [[NSAutoreleasePool alloc] init] and [pool release] which I could maybe swizzle in the objc layer, the compiler injects calls to two private C functions in the runtime: objc_autoreleasePoolPush() and objc_autoreleasePoolPop()... and for whatever reason, those C functions do not in turn call [[NSAutoreleasePool alloc] init] and [pool release].
I had previously thought that calling objc_autoreleasePoolPush() was actually creating a new pool and pushing it onto the pool stack, but the return value is 0x01, which is maybe some sort of sentinel/placeholder value — it's definitely not an instance of NSAutoreleasePool.
Anyway, what I need is to either:
A: intercept allocation/initialization/deallocation of NSAutoreleasePools injected during compilation of #autoreleasepool so that I can alloc/init/dealloc instances of my own autorelease pool class
or
B: implement a separate, post-compilation binary patching step that overwrites calls to these C functions with calls to my own corresponding function addresses
Any ideas on either of these options?

...those C functions do not in turn call [[NSAutoreleasePool alloc] init] and [pool release].
A decent part of Objective-C runtime library was re-written in C++ in the latest versions, the autorelease pool block is not an exception - the use of NSAutoreleasePool was completely replaced with the functions you found, which under the hood call static methods of AutoreleasePoolPage C++ class. It means that nowadays #autorelease has nothing to do with NSAutoreleasePool apart from common past.
I had previously thought that calling objc_autoreleasePoolPush() was actually creating a new pool and pushing it onto the pool stack, but the return value is 0x01...
According to the clang documentation objc_autoreleasePoolPush() returns an opaque “handle” to a new autorelease pool. An "opaque handle" in this case is just a void pointer to an actual autorelease object (which is not an instance of NSAutoreleasePool in this case), so you don't have any access to its interface (but you can later use it to pass as an argument to other functions of the same section).
what I need is to either:
A: intercept allocation/initialization/deallocation of NSAutoreleasePools injected during compilation of #autoreleasepool so that I can alloc/init/dealloc instances of my own autorelease pool class
The only way to enforce use of NSAutoreleasePool by #autoreleasepool block is to compile the Objective-C code with legacy runtime (macosx-10.6 or earlier).
or
B: implement a separate, post-compilation binary patching step that overwrites calls to these C functions with calls to my own corresponding function addresses
I'm not an expert with that, but it seems to be the only viable option if you want to inject your own functionality in place of #autoreleasepool blocks.
However for debugging purposes you may get use of how clang handles undefined behaviour scenario with ODR violations for C functions (it doesn't fail at linking step, but which function gets called is not certain). You surely should not use such a code for any serious project.
#import ObjectiveC;
#include <stdio.h>
#pragma mark Autorelease functions
void *objc_autoreleasePoolPush(void) {
printf("AR New init\n");
static void *handle = &handle;
return handle;
}
void objc_autoreleasePoolPop(void *handle) {
printf("AR New drain\n");
}
#pragma mark Autorelease object
#interface NSAutoreleasePool : NSObject
- (void)drain;
#end
#implementation NSAutoreleasePool
- (instancetype)init {
if (self = [super init]) {
printf("AR Old init\n");
}
return self;
}
- (void)drain {
printf("AR Old drain\n");
}
#end
#pragma mark Main
int main(int argc, const char * argv[]) {
#autoreleasepool {
NSObject *object = [[NSObject new] autorelease];
}
return 0;
}
To summarise, if you run this code with some legacy runtime, it will use the custom NSAutoreleasePool in place of #autoreleasepool:
% clang -ObjC -fmodules -lobjc -fobjc-runtime=macosx-10.6 -o main main.m
% ./main
AR Old init
AR Old drain
With the latest runtime, the program will use the redefined functions (again, this is just for demo purposes, avoid using such an approach in your code):
% clang -ObjC -fmodules -lobjc -o main main.m
% ./main
AR New init
AR New drain
EDIT
For the ODR part, I actually was convinced that upon linking lld may end up with undefined behaviour, since two symbols with the same name exist in a program, however after digging a little deeper into the question, it looks like the rules are well-defined (at least for llvm linker):
SymbolTable
SymbolTable is basically a hash table from strings to Symbols with
logic to resolve symbol conflicts. It resolves conflicts by symbol
type.
If we add Defined and Undefined symbols, the symbol table will keep the former.
If we add Defined and Lazy symbols, it will keep the former.
If we add Lazy and Undefined, it will keep the former, but it will also trigger the Lazy symbol to load the archive member to
actually resolve the symbol.
Whether it's reliable outside of macOS / llvm ecosystem is way beyond my expertise

Related

Auto release pool, Objective-c with C++ using it properly with multiple languages

I am learning how to use Objective-c which I have never used before with C++ and C. I am realizing that Objective-c really likes you to release objects. This is a .mm C++ based application, more C++ will be used than Objective-c.
In this example should I simply just call CFRelease(object) after it's used in the screenshot function. Or is it good practice to use #autoreleasepool within your functions.
I was not sure if #autoreleasepool releases everything regarding objects that require CFRelease.
bool screenshot() {
CGImageRef _Image;
CFStringRef _Filename, _Format;
CFURLRef _URLRef;
CGImageDestinationRef _Destination;
_Image = CGWindowListCreateImage(CGRectInfinite, (1 << 0), (0), (1 << 0));
_Filename = CFStringRef(#"screenshot.jpg");
_Format = CFStringRef(#"public.jpeg");
_URLRef = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, _Filename, CFURLPathStyle(0), 0);
_Destination = CGImageDestinationCreateWithURL(_URLRef, _Format, 1, nullptr);
CGImageDestinationAddImage(_Destination, _Image, nullptr);
// Use it here?
#autoreleasepool {
if ( CGImageDestinationFinalize(_Destination) ) {
CFRelease(_Destination); // Or individually release
CFRelease(_URLRef); // Or individually release
return true;
} else {
return false;
}
}
}
int main(int argc, const char **argv) {
// Here only, possibly?
#autoreleasepool {
screenshot();
}
return 0;
}
Any ObjC code will need a wrapping #autoreleasepool at some level. So, it's a good idea to have it in main() at the very least.
The rest of your stuff is more strictly CFFoundation, which is C and not (necessarily) Objective-C. You will need to call CFRelease on the two you have, as well as _Image, and you should not need an extra autorelease pool around them, as once the retain count goes to zero on CFRelease the memory will be deallocated directly. If you use CFAutorelease() instead, then you do need the pool, and the objects will live until the nearest wrapping autoreleasepool goes out of scope, at which point it will call CFRelease() (or the -release ObjC method) on all objects in the pool.
So an autorelease is a sort of delayed release, when you still want to use the object in the local scope afterwards. It's often used for returned values. If you are using pure CFFoundation and call CFRelease(), then there may not be anything actually autoreleased so there won't be anything in the pool.
You should be using CFRelease() (or CFAutorelease) on the three created objects regardless if the routine returns true or false -- you are done with them.
If you are using regular ObjC, they will likely autorelease objects somewhere below. You can use autoreleasepools if there is likely a large amount of memory or number of autoreleased objects you want to clean up, possibly before moving to other tasks. Or sometimes it's done once per loop.
BTW, you can use CFSTR("public.jpg") to get constant CFStringRefs, rather than converting them from constant ObjC NSStrings, but it probably works fine either way.

concept of object from c/python to object-c

I have experience on C and Python,
I learned the Object-C today,
I want to make sure if my concept is correct ?
I don't know why should I put a statement in a bracket
[pt setX: 8];
Isn't pt setX: 8 meaningful enough ?
If brackets is only for readable, why I got errors in this picture,
I just want to know when should I use the bracket , and when isn't need.
Is pt setX: 8 similar to pt.setX(8) in Python or C-like language?
To create a object,
You have to define .h .m,
In C, you can define and implement both in a .c file , but can not in object-c ?
If you want autorelease the object memory without explicitly free the memory in manual,
Just put your code in the #autoreleasepool block, right ?
#autoreleasepool {
MyPoint* pt = [MyPoint alloc];
// call constructor
pt = [pt init];
[pt print];
[pt getArea];
[pt setX: 8];
[pt setY: 99];
[pt print];
[pt getArea];
}
MyPoint.m
//
// MyPoint.m
// hello_world
//
// Created by poc on 2014/4/27.
// Copyright (c) 2014年 poc. All rights reserved.
//
import "MyPoint.h"
#implementation MyPoint
- (void) print
{
NSLog(#"X =%i and Y= %i", _x, _y);
}
- (void) getArea
{
NSLog(#"Area is %i", _x*_y);
}
- (void) setX:(int)aX
{
_x = aX;
}
- (int) getX
{
return _x;
}
- (void) setY:(int)aY
{
_y = aY;
}
- (int) getY
{
return _y;
}
#end
Is pt setX: 8 not meaningful enough ?
No, it's not. Let's assume situation when you want use result of method invocation as object
pt area intValue // without brackets it's a mess
[[pt area] intValue]; // looks readable now
Is pt setX: 8 similar to pt.setX(8) in Python or C-like language?
Yes, it similar. But you need square brackets
In C, you can define and implement both in a .c file , but can not in object-c ?
Analog of .c file for obj-c is named .m. There you can do the same stuff as you can in .c, importing of .m is really bad practice, it leads you in majority of cases to incorrect linking and, eventually in failure of build. Also it good way to separate private and public interfaces. .h contains public interface to class, you import .h and see only public methods and class variables, while .m contains private methods and variable that you don't want to expose.
If you want autorelease the object memory without explicitly free the memory in manual,
Just put your code in the #autoreleasepool block, right ?
No, it's not. You can't count on autoreleasing of variables you puts there. Autorelease pool created for another purpose. If you want to know why - read this.
I encourage you to use ARC (automatic reference counting), it's enabled by default in latest project templates in Xcode. This way you don't need to worry about memory management, while you correctly use naming convention.
I don't know why should I put a statement in a bracket
That's just the syntax for method calls. Why are parentheses required around arguments in C and Python? Syntax. Other languages don't require parentheses or brackets for method and function calls (e.g. Smalltalk, Ruby and Perl, though parentheses allow you to be more expressive) because they use different syntax. Smalltalk, in particular, is similar to Objective-C method calls, but without the brackets (not coincidentally, since Smalltalk inspired Objective-C).
Is pt setX: 8 similar to pt.setX(8) in Python or C-like language?
Yes. In particular, [pt setX: 8] calls method setX on (or, if you prefer, sends message setX to) object pt, passing 8 as a parameter.
In C, you can define and implement both in a .c file , but can not in object-c ?
Keep in mind that anything declared solely in a compilation unit (a ".c" file) isn't accessible in other compilation units. With Objective-C, you can declare both static variables (as you might in C) and methods in a compilation unit (which have that ".m" extension), but they are effectively private.
If you want autorelease the object memory without explicitly free the memory in manual, [j]ust put your code in the #autoreleasepool block, right ?
An #autoreleasepool block isn't responsible for keeping track of object lifetime; see "Why is autorelease (#autoreleasepool) still needed with ARC?" for what it does. See also "Transitioning to ARC Release Notes" for info on Automatic Reference Counting (ARC) and "Memory management" for info on the older approach (manual reference counting), which is what ARC does under the hood.

Objective C chaining calls

I'm new to Objective C so please forgive me if this question seems stupid.
First sample:
int main(int argc, const char* argv[])
{
#autoreleasepool
{
MyCoolDelegate* myCoolDelegate = [[MyCoolDelegate alloc] init];
[[NSApplication sharedApplication] setDelegate: myCoolDelegate];
return NSApplicationMain(argc, argv);
}
}
Second sample:
int main(int argc, const char* argv[])
{
#autoreleasepool
{
[[NSApplication sharedApplication] setDelegate: [[MyCoolDelegate alloc] init]];
return NSApplicationMain(argc, argv);
}
}
As C++ programmer I expect both main functions should have the same behaviour, but second main crashes on return NSApplicationMain(argc, argv); while first one sets the delegate and works as expected.
Can you please explain what is the difference between these samples? Is there some black magic around temporary objects in Objective C(I assume [MyCoolDelegate alloc] init] will return a temporary object of type MyCoolDelegate)?
To elaborate on #tenfour’s answer, this line:
MyCoolDelegate *myCoolDelegate = [[MyCoolDelegate alloc] init];
Has an implicit “__strong” in it, so it really means this:
__strong MyCoolDelegate *myCoolDelegate = [[MyCoolDelegate alloc] init];
If you change your first line to something like this:
__unsafe_unretained MyCoolDelegate *myCoolDelegate = [[MyCoolDelegate alloc] init];
Then you should see the same (bad) behavior in both cases.
You probably want to make myCoolDelegate an instance variable, static variable, or create it in a xib file (like the Xcode template you get from File > New Project… > Cocoa Application does).
Actually, both examples are technically wrong. One "accidentally works" because the compiler isn't (currently!) performing the legal optimization to release myCoolDelegate as soon as it's used for the last time, which is before the NSApplicationMain call.
Per the spec, "By default, local variables of automatic storage duration do not have precise lifetime semantics. Such objects are simply strong references which hold values of retainable object pointer type, and these values are still fully subject to the optimizations on values under local control."
Usually -setDelegate: methods don't retain/strongly-reference things, to prevent strong reference cycles, where two objects both keep each other from being deallocated. For compatibility, NSApplication uses an __unsafe_unretained reference to it's delegate instead of a (usually preferable) __weak reference (this might change in future OS X versions course). So when NSApplication tries to talk to it's delegate after it has been deallocated, you get a crash. The delegate can be deallocated here because nothing is strongly referencing it after the -setDelegate: call.
In summary: using an implicit temporary variable, or an explicit local variable only keep an object alive until the variable's last use. They do not guarantee that the object is kept alive as long as the variable is in scope. It's unfortunate that the compiler isn't being as aggressive as it could be, which makes an explicit local variable appear to extend an object's life time more than it's guaranteed to. You might see different behavior if you turned on more optimizations. You need to make myCoolDelegate a "longer lived" kind of variable (ivar, staic, or global) or use the objc_precise_lifetime attribute when declaring it.
__attribute__((objc_precise_lifetime)) MyCoolDelegate* myCoolDelegate = [[MyCoolDelegate alloc] init];
This situation is complicated, but it doesn't come up in practice much, because things that are delegates of another object are almost always referenced through an ivar, or something "long lived", not just a local variable.
In your first example, myCoolDelegate holds a reference to the object, keeping it alive until myCoolDelegate goes out of scope at the end of your #autoreleasepool block where it is automatically released deallocated.
In your second example, the MyCoolDelegate object you create is not retained by any local variable. You are creating a temporary which has a retain count only for the duration of the statement.
If setDelegate retains the object, the object will continue to live with a retain count of 1, and your app won't crash when the application tries to use it.
If on the other hand setDelegate only keeps a weak reference, then your app will crash because its retain count is 0 after calling setDelegate returns, so the object is deallocated before NSApplicationMain.

How to interact with #autoreleasepool

Based on Bavarious's answer to this SO question, I am led to believe that #autoreleasepool is now an Objective-C language feature if you build with LLVM/clang.
This being the case, how does one rewrite the following code to use an #autoreleasepool instead of an NSAutoreleasePool in a non-ARC environment?
[NSAutoreleasePool addObject:anObject]; // (*)
Background: I essentially want to write a custom implementation of -autorelease that does not in any way interact with the NSAutoreleasePool class:
#autoreleasepool {
SomeCls *obj = [[SomeCls alloc] init];
[obj autorelease]; // Does not go through an NSAutoreleasePool object
// ...
}
#autoreleasepool { } is a new language feature meant to obviate the need to drain the current pool at every exit point of a function. Now, instead of having to write:
void f(void) {
//Make a new pool
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
//Every inner scope that exits prematurely requires a drain
if (life_is_good) {
for (int i = 0; i < 1000; i++) {
NSObject *obj = [[[NSObject alloc]init]autorelease];
//breaks out of the loop, and the function, so drain the pool
if (life_is_bad) {
[pool drain];
return;
}
}
//Life gets bad below here, so return
[pool drain];
return;
}
//end of function requires drain.
[pool drain];
}
You can wrap the entire function in an #autoreleasepool { } directive and the compiler will insert the proper drains where the function returns:
void f(void) {
//Make a new pool
#autoreleasepool {
if (life_is_good) {
for (int i = 0; i < 1000; i++) {
NSObject *obj = [[[NSObject alloc]init]autorelease];
//breaks out of the loop, and the function, so drain the pool
if (life_is_bad) {
//[pool drain]; auto-drain
return;
}
}
//[pool drain]; auto-drain
return;
}
//[pool drain]; auto-drain
}
}
I have no idea why you would want to forgo the automatic pool mechanism, as it handles a huge amount of work for you (page management, per-thread pool management, releasing objects in a timely yet efficient manner), but it shouldn't be that much of a hassle to get a primitive NSAutoreleasePool up and running. Any autoreleasepool would require a page manager (malloc() and realloc()), pointer storage (a simple array), and some way to detect whether or not the current scope in which it is being used has exited (-drain). A simple pool could just be a thread-safe singleton, but be wary of how many objects you try to insert and remove at one time with that implementation. You just might segfault if you try to allocate too many hot pages for too many objects.
Based on Bavarious's answer to this SO question, I am led to believe that #autoreleasepool is now an Objective-C language feature if you build with LLVM/clang.
Correct.
This being the case, how does one rewrite the following code to use an #autoreleasepool instead of an NSAutoreleasePool in a non-ARC environment?
[NSAutoreleasePool addObject:anObject]; // (*)
Doc: Normally you don’t invoke this method directly—you send autorelease to object instead.
#autoreleasepool {
id anObject = ...;
[anObject autorelease];
}
Background: I essentially want to write a custom implementation of -autorelease that does not in any way interact with the NSAutoreleasePool class:
You can't even subclass NSAutoreleasePool any longer (in a meaningful way). Unless you never pass the object to other APIs which are free to autorelease, your objects are going to end up in the current autorelease pool. The mechanics of this today is not even object based.
If this is impossible, I would be open to workaround suggestions not involving NSAutoreleasePool.
Not certain what problem you are trying to solve, but you can extend lifetimes using:
NSMutableArray * fauxAutoreleasePool = NSMutableArray.new;
id anObject = ...;
[fauxAutoreleasePool addObject:anObject];
...
[fauxAutoreleasePool removeAllObjects]; // << explicitly drain, which also happens when the array is destroyed
Of course, you could write your own implementation. Why you would write your own is still a mystery, and not a good idea for production code (#autoreleasepool works well).
Though I have already marked an answer as accepted, and offered a bounty at the time, I have since found the true answer I was searching for and realised my question wasn't very clear - primarily because I didn't know what to ask.
How to interact with #autoreleasepool:
When the compiler comes across an #autoreleasepool { } block, it automatically inserts two function calls. At the opening of the block it inserts the C function call:
void *_objc_autoreleasePoolPush(void);
At the close of the #autoreleasepool block (including when a return or break is encountered within - but NOT when an exception is thrown according to the LLVM docs) the compiler inserts the C function call:
_objc_autoreleasePoolPop(void *ctxt); // ctxt is Apple's label for the param
I believe the void *ctxt parameter is an indicator of where the current #autoreleasepool started (really only useful in Apple's implementation - see here). In any case I found it can easily be ignored in custom implementations.
The -autorelease selector:
Essentially the methodology is this:
Create (if outermost block) or mark (if inner block) an autorelease pool object (in C or C++) in _objc_autoreleasePoolPush(). It seems easiest to me to use a Stack data structure for this but YMMV.
Ensure this object is in scope within the -autorelease selector, or you have a fail-safe way of accessing it.
Add the object to the autorelease pool object (in whatever way that may be) inside -autorelease.
In _objc_autoreleasePoolPop(void *), send the -release message to every item in the autorelease pool object until the marker set in _objc_autoreleasePoolPush() is reached (or you reach the bottom of the pool). Then do any additional required cleanup.
Final notes on threading:
Objective-C #autoreleasepools are supposed to be thread-local. That is, each thread has its own (if it requires one). As a result, _objc_autoreleasePoolPush() must have some way of determining whether the current thread already has an active autorelease pool and create the object if it does not.
Similarly, this is why, when creating a thread, the thread must first open an #autoreleasepool { } block before it does anything else (in Objective-C), and the final thing it must do is close that #autoreleasepool block (implicitly through break or return or with explicit fall-through).
Three final observations:
If you wish to implement your own autorelease pool object, you will need some form of thread-local storage to store it.
That last point about threading is why every Objective-C program must begin with an #autoreleasepool { } block in main().
This is why Apple ask you to use the NSThread class and GCD rather than DIY threading - they take care of all of this for you!
At the end of the #autoreleasepool block, the autoreleased objects are sent a release message.
If you want to reimplement the autorelease method, you may not want to directly send release messages to your NSObjectsubclass. If so, reimplementing release with some special behavior could do your business.
Background: I essentially want to write a custom implementation of
-autorelease that does not in any way interact with the NSAutoreleasePool class:
What makes you think that -autorelease interacts with NSAutoreleasePool?
As long as you are running on iOS 5+ or Mac OS X 10.7+, both the #autoreleasepool and -[NSObject autorelease] will use the runtime autorelease pool management functions, and have nothing to do with NSAutoreleasePool at all (and NSAutoreleasePool on those OS versions is simply a wrapper around the runtime functions).

Why is #autoreleasepool still needed with ARC?

For the most part with ARC (Automatic Reference Counting), we don't need to think about memory management at all with Objective-C objects. It is not permitted to create NSAutoreleasePools anymore, however there is a new syntax:
#autoreleasepool {
…
}
My question is, why would I ever need this when I'm not supposed to be manually releasing/autoreleasing ?
EDIT: To sum up what I got out of all the anwers and comments succinctly:
New Syntax:
#autoreleasepool { … } is new syntax for
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
…
[pool drain];
More importantly:
ARC uses autorelease as well as release.
It needs an auto release pool in place to do so.
ARC doesn't create the auto release pool for you. However:
The main thread of every Cocoa app already has an autorelease pool in it.
There are two occasions when you might want to make use of #autoreleasepool:
When you are in a secondary thread and there is no auto release pool, you must make your own to prevent leaks, such as myRunLoop(…) { #autoreleasepool { … } return success; }.
When you wish to create a more local pool, as #mattjgalloway has shown in his answer.
ARC doesn't get rid of retains, releases and autoreleases, it just adds in the required ones for you. So there are still calls to retain, there are still calls to release, there are still calls to autorelease and there are still auto release pools.
One of the other changes they made with the new Clang 3.0 compiler and ARC is that they replaced NSAutoReleasePool with the #autoreleasepool compiler directive. NSAutoReleasePool was always a bit of a special "object" anyway and they made it so that the syntax of using one is not confused with an object so that it's generally a bit more simple.
So basically, you need #autoreleasepool because there are still auto release pools to worry about. You just don't need to worry about adding in autorelease calls.
An example of using an auto release pool:
- (void)useALoadOfNumbers {
for (int j = 0; j < 10000; ++j) {
#autoreleasepool {
for (int i = 0; i < 10000; ++i) {
NSNumber *number = [NSNumber numberWithInt:(i+j)];
NSLog(#"number = %p", number);
}
}
}
}
A hugely contrived example, sure, but if you didn't have the #autoreleasepool inside the outer for-loop then you'd be releasing 100000000 objects later on rather than 10000 each time round the outer for-loop.
Update:
Also see this answer - https://stackoverflow.com/a/7950636/1068248 - for why #autoreleasepool is nothing to do with ARC.
Update:
I took a look into the internals of what's going on here and wrote it up on my blog. If you take a look there then you will see exactly what ARC is doing and how the new style #autoreleasepool and how it introduces a scope is used by the compiler to infer information about what retains, releases & autoreleases are required.
#autoreleasepool doesn't autorelease anything. It creates an autorelease pool, so that when the end of block is reached, any objects that were autoreleased by ARC while the block was active will be sent release messages. Apple's Advanced Memory Management Programming Guide explains it thus:
At the end of the autorelease pool block, objects that received an autorelease message within the block are sent a release message—an object receives a release message for each time it was sent an autorelease message within the block.
People often misunderstand ARC for some kind of garbage collection or the like. The truth is that, after some time people at Apple (thanks to llvm and clang projects) realized that Objective-C's memory administration (all the retains and releases, etc.) can be fully automatized at compile time. This is, just by reading the code, even before it is run! :)
In order to do so there is only one condition: We MUST follow the rules, otherwise the compiler would not be able to automate the process at compile time. So, to ensure that we never break the rules, we are not allowed to explicitly write release, retain, etc. Those calls are Automatically injected into our code by the compiler. Hence internally we still have autoreleases, retain, release, etc. It is just we don't need to write them anymore.
The A of ARC is automatic at compile time, which is much better than at run time like garbage collection.
We still have #autoreleasepool{...} because having it does not break any of the rules, we are free create/drain our pool anytime we need it :).
Autorelease pools are required for returning newly created objects from a method. E.g. consider this piece of code:
- (NSString *)messageOfTheDay {
return [[NSString alloc] initWithFormat:#"Hello %#!", self.username];
}
The string created in the method will have a retain count of one. Now who shall balance that retain count with a release?
The method itself? Not possible, it has to return the created object, so it must not release it prior to returning.
The caller of the method? The caller does not expect to retrieve an object that needs releasing, the method name does not imply that a new object is created, it only says that an object is returned and this returned object may be a new one requiring a release but it may as well be an existing one that doesn't. What the method does return may even depend on some internal state, so the the caller cannot know if it has to release that object and it shouldn't have to care.
If the caller had to always release all returned object by convention, then every object not newly created would always have to be retained prior to returning it from a method and it would have to be released by the caller once it goes out of scope, unless it is returned again. This would be highly inefficient in many cases as one can completely avoid altering retain counts in many cases if the caller will not always release the returned object.
That's why there are autorelease pools, so the first method will in fact become
- (NSString *)messageOfTheDay {
NSString * res = [[NSString alloc] initWithFormat:#"Hello %#!", self.username];
return [res autorelease];
}
Calling autorelease on an object adds it to the autorelease pool, but what does that really mean, adding an object to the autorelease pool? Well, it means telling your system "I want you to to release that object for me but at some later time, not now; it has a retain count that needs to be balanced by a release otherwise memory will leak but I cannot do that myself right now, as I need the object to stay alive beyond my current scope and my caller won't do it for me either, it has no knowledge that this needs to be done. So add it to your pool and once you clean up that pool, also clean up my object for me."
With ARC the compiler decides for you when to retain an object, when to release an object and when to add it to an autorelease pool but it still requires the presence of autorelease pools to be able to return newly created objects from methods without leaking memory. Apple has just made some nifty optimizations to the generated code which will sometimes eliminate autorelease pools during runtime. These optimizations require that both, the caller and the callee are using ARC (remember mixing ARC and non-ARC is legal and also officially supported) and if that is actually the case can only be known at runtime.
Consider this ARC Code:
// Callee
- (SomeObject *)getSomeObject {
return [[SomeObject alloc] init];
}
// Caller
SomeObject * obj = [self getSomeObject];
[obj doStuff];
The code that the system generates, can either behave like the following code (that is the safe version that allows you to freely mix ARC and non-ARC code):
// Callee
- (SomeObject *)getSomeObject {
return [[[SomeObject alloc] init] autorelease];
}
// Caller
SomeObject * obj = [[self getSomeObject] retain];
[obj doStuff];
[obj release];
(Note the retain/release in the caller is just a defensive safety retain, it's not strictly required, the code would be perfectly correct without it)
Or it can behave like this code, in case that both are detected to use ARC at runtime:
// Callee
- (SomeObject *)getSomeObject {
return [[SomeObject alloc] init];
}
// Caller
SomeObject * obj = [self getSomeObject];
[obj doStuff];
[obj release];
As you can see, Apple eliminates the atuorelease, thus also the delayed object release when the pool is destroyed, as well as the safety retain. To learn more about how that is possible and what's really going on behind the scenes, check out this blog post.
Now to the actual question: Why would one use #autoreleasepool?
For most developers, there's only one reason left today for using this construct in their code and that is to keep the memory footprint small where applicable. E.g. consider this loop:
for (int i = 0; i < 1000000; i++) {
// ... code ...
TempObject * to = [TempObject tempObjectForData:...];
// ... do something with to ...
}
Assume that every call to tempObjectForData may create a new TempObject that is returned autorelease. The for-loop will create one million of these temp objects which are all collected in the current autoreleasepool and only once that pool is destroyed, all the temp objects are destroyed as well. Until that happens, you have one million of these temp objects in memory.
If you write the code like this instead:
for (int i = 0; i < 1000000; i++) #autoreleasepool {
// ... code ...
TempObject * to = [TempObject tempObjectForData:...];
// ... do something with to ...
}
Then a new pool is created every time the for-loop runs and is destroyed at the end of each loop iteration. That way at most one temp object is hanging around in memory at any time despite the loop running one million times.
In the past you often had to also manage autoreleasepools yourself when managing threads (e.g. using NSThread) as only the main thread automatically has an autorelease pool for a Cocoa/UIKit app. Yet this is pretty much legacy today as today you probably wouldn't use threads to begin with. You'd use GCD DispatchQueue's or NSOperationQueue's and these two both do manage a top level autorelease pool for you, created before running a block/task and destroyed once done with it.
It's because you still need to provide the compiler with hints about when it is safe for autoreleased objects to go out of scope.
Quoted from https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html:
Autorelease Pool Blocks and Threads
Each thread in a Cocoa application maintains its own stack of
autorelease pool blocks. If you are writing a Foundation-only program
or if you detach a thread, you need to create your own autorelease
pool block.
If your application or thread is long-lived and potentially generates
a lot of autoreleased objects, you should use autorelease pool blocks
(like AppKit and UIKit do on the main thread); otherwise, autoreleased
objects accumulate and your memory footprint grows. If your detached
thread does not make Cocoa calls, you do not need to use an
autorelease pool block.
Note: If you create secondary threads using the POSIX thread APIs
instead of NSThread, you cannot use Cocoa unless Cocoa is in
multithreading mode. Cocoa enters multithreading mode only after
detaching its first NSThread object. To use Cocoa on secondary POSIX
threads, your application must first detach at least one NSThread
object, which can immediately exit. You can test whether Cocoa is in
multithreading mode with the NSThread class method isMultiThreaded.
...
In Automatic Reference Counting, or ARC, the system uses the same
reference counting system as MRR, but it insertsthe appropriate memory
management method callsfor you at compile-time. You are strongly
encouraged to use ARC for new projects. If you use ARC, there is
typically no need to understand the underlying implementation
described in this document, although it may in some situations be
helpful. For more about ARC, see Transitioning to ARC Release Notes.
TL;DR
Why is #autoreleasepool still needed with ARC?
#autoreleasepool is used by Objective-C and Swift to work with autorelese inside
When you work with pure Swift and allocate Swift objects - ARC handles it
But if you decide call/use Foundation/Legacy Objective-C code(NSData, Data) which uses autorelese inside then #autoreleasepool in a rescue
//Swift
let imageData = try! Data(contentsOf: url)
//Data init uses Objective-C code with [NSData dataWithContentsOfURL] which uses `autorelese`
Long answer
MRC, ARC, GC
Manual Reference Counting(MRC) or Manual Retain-Release(MRR) as a developer you are responsible for counting references on objects manually
Automatic Reference Counting(ARC) was introduced in iOS v5.0 and OS X Mountain Lion with xCode v4.2
Garbage Collection(GC) was available for Mac OS and was deprecated in OS X Mountain Lion. Must Move to ARC
Reference count in MRC and ARC
//MRC
NSLog(#"Retain Count: %d", [variable retainCount]);
//ARC
NSLog(#"Retain Count: %ld", CFGetRetainCount((__bridge CFTypeRef) variable));
Every object in heap has an integer value which indicates how many references are pointed out on it. When it equals to 0 object is deallocated by system
Allocating object
Working with Reference count
Deallocating object. deinit is called when retainCount == 0
MRC
A *a1 = [[A alloc] init]; //this A object retainCount = 1
A *a2 = a1;
[a2 retain]; //this A object retainCount = 2
// a1, a2 -> object in heap with retainCount
Correct way to release an object:
release If only this - dangling pointer. Because it still can point on the object in heap and it is possible to send a message
= nil If only this - memory leak. deinit will not be called
A *a = [[A alloc] init]; //++retainCount = 1
[a release]; //--retainCount = 0
a = nil; //guarantees that even somebody else has a reference to the object, and we try to send some message thought variable `a` this message will be just skipped
Working with Reference count(Object owner rules):
(0 -> 1) alloc, new, copy, mutableCopy
(+1) retain You are able to own an object as many times as you need(you can call retain several times)
(-1) release If you an owner you must release it. If you release more than retainCount it will be 0
(-1) autorelease Adds an object, which should be released, to autorelease pool. This pool will be processed at the end of RunLoop iteration cycle(it means when all tasks will be finished on the stack)[About] and after that release will be applied for all objects in the pool
(-1) #autoreleasepool Forces process an autorelease pool at the end of block. It is used when you deal with autorelease in a loop and want to clear resources ASAP. If you don't do it your memory footprint will be constantly increasing
autorelease is used in method calls when you allocate a new object there and return it
- (B *)foo {
B *b1 = [[B alloc] init]; //retainCount = 1
//fix - correct way - add it to fix wrong way
//[b1 autorelease];
//wrong way(without fix)
return b;
}
- (void)testFoo {
B *b2 = [a foo];
[b2 retain]; //retainCount = 2
//some logic
[b2 release]; //retainCount = 1
//Memory Leak
}
#autoreleasepool example
- (void)testFoo {
for(i=0; i<100; i++) {
B *b2 = [a foo];
//process b2
}
}
ARC
One of biggest advantage of ARC is that it automatically insert retain, release, autorelease under the hood in Compile Time and as developer you should not take care of it anymore
Enable/Disable ARC
//enable
-fobjc-arc
//disable
-fno-objc-arc
Variants from more to less priority
//1. local file - most priority
Build Phases -> Compile Sources -> Compiler Flags(Select files -> Enter)
//2. global
Build Settings -> Other C Flags(OTHER_CFLAGS)
//3. global
Build Settings -> Objective-C Automatic Reference Counting(CLANG_ENABLE_OBJC_ARC)
Check if ARC is enabled/disabled
Preprocessor __has_feature function is used
__has_feature(objc_arc)
Compile time
// error if ARC is Off. Force to enable ARC
#if ! __has_feature(objc_arc)
#error Please enable ARC for this file
#endif
//or
// error if ARC is On. Force to disable ARC
#if __has_feature(objc_arc)
#error Please disable ARC for this file
#endif
Runtime
#if __has_feature(objc_arc)
// ARC is On
NSLog(#"ARC on");
#else
// ARC is Off
NSLog(#"ARC off");
#endif
Reverse engineering(for Objective-C)
//ARC is enabled
otool -I -v <binary_path> | grep "<mrc_message>"
//e.g.
otool -I -v "/Users/alex/ARC_experiments.app/ARC_experiments" | grep "_objc_release"
//result
0x00000001000080e0 748 _objc_release
//<mrc_message>
_objc_retain
_objc_release
_objc_autoreleaseReturnValue
_objc_retainAutoreleaseReturnValue
_objc_retainAutoreleasedReturnValue
_objc_storeStrong
Tool to Migrate Objective-C MRC to ARC
ARC generates errors where you should manually remove retain, release, autorelease and others issues
Edit -> Convert -> To Objective-C ARC...
New Xcode with MRC
If you enable MRC you get next errors(warnings)(but the build will be successful)
//release/retain/autorelease/retainCount
'release' is unavailable: not available in automatic reference counting mode
ARC forbids explicit message send of 'release'
There seems to be a lot of confusion on this topic (and at least 80 people who probably are now confused about this and think they need to sprinkle #autoreleasepool around their code).
If a project (including its dependencies) exclusively uses ARC, then #autoreleasepool never needs to be used and will do nothing useful. ARC will handle releasing objects at the correct time. For example:
#interface Testing: NSObject
+ (void) test;
#end
#implementation Testing
- (void) dealloc { NSLog(#"dealloc"); }
+ (void) test
{
while(true) NSLog(#"p = %p", [Testing new]);
}
#end
displays:
p = 0x17696f80
dealloc
p = 0x17570a90
dealloc
Each Testing object is deallocated as soon as the value goes out of scope, without waiting for an autorelease pool to be exited. (The same thing happens with the NSNumber example; this just lets us observe the dealloc.) ARC does not use autorelease.
The reason #autoreleasepool is still allowed is for mixed ARC and non-ARC projects, which haven't yet completely transitioned to ARC.
If you call into non-ARC code, it may return an autoreleased object. In that case, the above loop would leak, since the current autorelease pool will never be exited. That's where you'd want to put an #autoreleasepool around the code block.
But if you've completely made the ARC transition, then forget about autoreleasepool.