POSIX callbacks and NSAutoreleasePool with ARC - objective-c

According to this Apple page, I've read that when interacting with Cocoa on a POSIX thread that I should create a NSAutoreleasePool.
If you are making Cocoa calls outside of the Application Kit’s main
thread—for example if you create a Foundation-only application or if
you detach a thread—you need to create your own autorelease pool.
Unfortunately, using NSAutoreleasePool is disallowed in ARC.
What should I do then to guarantee that there is always an pool available for any ARC code that is autoreleased?
Thanks!

Use #autoreleasepool.
#autoreleasepool
{
// make Cocoa calls here
}
This allows the compiler to reason properly about the lifetime of objects that cross the pool's boundary, which is a requirement for ARC. (That's why you can't use NSAutoreleasePool.) As a bonus, it's also faster.

Related

Objective-C #autoreleasepool?

I fairly new to Obj-C and am just starting out making little useless programs to help further my knowledge. I wanted to make sure I wasn't making any memory leaks. Does anything in the '#autoreleasepool' automatically release it's memory when the program ends?
Also if there are any bad habits, please let me know!
int main(int argc, const char * argv[])
{
#autoreleasepool {
Fraction* fractionOne = [[Fraction alloc]init];
Fraction* fractionTwo = [[Fraction alloc]init];
Fraction* fractionThree = [[Fraction alloc]init];
[fractionOne setTo:1 over:2];
[fractionTwo setTo:1 over:4];
[fractionThree setTo:1 over:8];
[Fraction numberOfFractions];
return 0;
}
}
See Apple's discussion of Using Autorelease Pool Blocks in the Advanced Memory Management Programming Guide.
In short, no, it is not the case that "anything in the #autoreleasepool automatically release[s] its memory when the program ends" (or at least not as a function of the #autoreleasepool). The purpose in having an autorelease pool is to control when the memory is reclaimed from autorelease items, i.e. when will the pool be drained. But your code sample doesn't appear to employ any autoreleased items, so it is not really applicable here (unless the methods used autorelease objects internally).
The most common usage of autorelease pools is to reduce the memory high-water mark of your app. See Use Local Autorelease Pool Blocks to Reduce Peak Memory Footprint. It used to be used for thread programming, but now that we have operation and dispatch blocks, we don't have to write traditional threaded code anymore, so we don't have as many occasion to need separate autorelease pools in our multithreaded code.
With ARC turned on, code is added at compile time to explicitly release fractionOne, Two and Three, so they'll get released with ARC. Without ARC, the alloc is creating a retained instance of Fraction and your code hasn't either released explicitly (almost always better) or set these as autoreleased (almost always worse).
So without arc, you're leaking during the few milliseconds this program is running.
That's more or less what it does. But don't worry: just rely on ARC. It manages your memory for you!
Using ARC, the only place you'll really see #autoreleasepool is the main function. When you start making apps, you'll write your code elsewhere and will barely ever edit the "default" main function (given to you by the Xcode templates).
So don't worry about it! Your code is fine :)
The autorelease pool object is essentially a container during runtime that holds objects (so-called autoreleased objects) alive in memory until they are released, i.e. when the pool is drained. This will happen at the end of autorelease’s scope.
Autorelease Pool is part of the Manual Reference Counting (MRC) technique in Objective-C to manage an object’s lifecycle. MRC is one of the three memory management models, the other two being Automatic Garbage Collection and ARC (Automatic Reference Counting).
During runtime, we want to avoid having memory leaks. These are blocks of allocated memory (e.g. objects) that were once alive but are not referenced by any process anymore. If we have no way of accessing or releasing them by any other running code, they can create numerous issues, e.g. cluttering and reducing the amount of available memory. The concept of the Autorelease Pool helps to mitigate this risk.
References:
NSAutoreleasePool
Programming in Objective-C, Sixth Edition (2013) by Stephen G. Kochan

Memory Management in a Objective-C static library

I'm quite new to the Objectivce-C and I was wondering what is the correct way of memory management in a static library without ARC.
Lets say my library has a method that returns NSString*:
- (NSString *) foo
{
...
NSString *result = [[NSString alloc] initWithString:#"bar"];
return [result autorelease];
}
So as far as I understand, since foo allocated the NSString it also needs to release it (or queue it for releasing). NSString is a return value, so the only thing I can do is to autorelease it. This creates a problem: if library is used in a command line tool, the developer needs to know that foo needs an #autoreleasepool otherwise calling foo multiple times inside main #autoreleasepool with eat up memory. This seems to me like I'm delegating memory management from library to the app which seems like a terrible thing to do. Is there a better way to do this? Or can I somehow make it obvious for the developer that foo needs an #autoreleasepool?
Autorelease pools do not deallocate objects automatically; they need to be manually drained. In Cocoa applications, this is done by the main thread's run loop, so normally most of developers don't have to do anything for that and don't know about it.
However, in any long-running functions, like command-line tool's main, or a background thread, it's the programmer's responsibility to manually drain autorelease pool periodically.
You are following the global memory management rules and that's the right thing to do. There's no need to change anything; it's not about ARC or static libraries.
Every thread requires an autoreleasepool*. If your code is called and there is no pool in place then the thread hasn't been set up properly and this is a programmer error.
Unless you created the thread (or process) this isn't your responsibility and has nothing to do with lazy memory management on your behalf.
The reason methods don't indicate that they need an autoreleasepool to be in place is because an autorelease pool always has to be in place.
*Sure you can write Objective-c that doesn't use autorelease, and about which you can reason with almost certainty will never use autorelease when internals change. Such code would only be able to use a small subset of Cocoa, if any, and would likely be pretty terrible.

Objective C #autoreleasepool directive

I am reading a book which says (if I am not getting it wrong) wrapping some code with #autoreleasepool statement enables the ARC. First of all is this the case ?
My second concern is when I am doing some iOS example programs, although I enable ARC when creating a new project, I never see this directive being used anywhere (in the automatically generated code). Does this mean that ARC is not being used ? Any ideas/pointers is appreciated.
#autoreleasepool doesn't "enable" ARC. It's just the ARC way to use autorelease pools.
Before ARC, you used the NSAutoreleasePool class to set up an autorelease pool like this:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Code benefitting from a local autorelease pool.
[pool release];
But you're not allowed to call release when using ARC, so instead a new way to use autorelease pools was introduced:
#autoreleasepool {
// Code benefitting from a local autorelease pool.
}
#autoreleasepool blocks are more efficient than using an instance of NSAutoreleasePool directly; you can also use them even if you do not use ARC.
First off, the book is wrong. #autoreleasepool is orthogonal to ARC. You can use autoreleasepools without ARC and you can use ARC without autoreleasepools (but you shouldn't).
Secondly, the main thread of a project created using any of Xcode's default projects will have the autoreleasepool pool created for you. Any thread you create will need to create its own autorelease pool.
wrapping some code with #autoreleasepool statement enables the ARC
No. ARC is enabled by a compiler flag. #autoreleasepool is just a keyword used to create autorelease pools even if you're using ARC (because normally you would create and destroy them using alloc-init and release, respectively, but you can't send explicit release messages under ARC - that's why this keyword had been introduced.)
And if you enable ARC in Xcode/with the compiler/etc, it's enabled. Certainly, there are better solutions than the "autorelease everything" principle and that may be the cause of you not encountering this keyword in example code.
My second concern is when I am doing some iOS example programs, although I enable ARC when creating a new project, I never see this directive being used anywhere (in the automatically generated code). Does this mean that ARC is not being used ? Any ideas/pointers is appreciated.
You application does use this. Check out the main.m file in your project. You will find it there.

scope of autorelease pool

Does NSAutoreleasePool also covers variables in all the called methods?
If that's the only place where -isNotExpired is called, the auto release pool you've set up will contain objects autoreleased in -isNotExpired (including startDate).
Note that in a normal Cocoa application, NSApplicationMain() called in main() in main.m will create an autorelease pool for you, so this code wouldn't leak anyway. You generally only create your own autorelease pool in cases where you'll be generating lots of temporary objects with a short useful life (in a loop for instance) and want to keep your high water memory usage down.

NSBlockOperation and NSAutoreleasePool

Normally when you create an NSOperation subclass you are responsible for creating and releasing an NSAutoreleasePool in the -main method.
When you use an NSBlockOperation, do you need to create an autorelease pool in the block?
No. GCD (which NSOperationQueue is built on top of as of OS X 10.6 or iOS 4.2) manages autorelease pools for you, the same way that NSRunLoop does.
I don’t think so, as the work queues have their own pools already created for you.
Adam,
Your best bet is to read up on block memory behavior with objects. Here is the link for the iOS Blocks and Variables the bottom of this page has information regarding object types.
Frank