113

On page 17 of this WWDC14 presentation, it says

Working with Objective-C? Still have to manage autorelease pools
autoreleasepool { /* code */ }

What does that mean? Does it mean that if my code base doesn't have any Objective-C files, autoreleasepool {} is unnecessary?

In an answer of a related question, there is an example where autoreleasepool can be useful:

- (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);
            }
        }
    }
}

If the code above gets translated into Swift with autoreleasepool dropped, will Swift be smart enough to know that the number variable should be released after the first } (like some other languages does)?

Community
  • 1
  • 1
Ethan
  • 18,584
  • 15
  • 51
  • 72
  • 1
    There appears to be no documentation on `autoreleasepool` in Swift. I [expanded on your question and asked it in the dev forums](https://devforums.apple.com/thread/245787). – Aaron Brager Sep 16 '14 at 07:32

3 Answers3

246

The autoreleasepool pattern is used in Swift when returning autorelease objects (created by either your Objective-C code or using Cocoa classes). The autorelease pattern in Swift functions much like it does in Objective-C. For example, consider this Swift rendition of your method (instantiating NSImage/UIImage objects):

func useManyImages() {
    let filename = pathForResourceInBundle
    
    for _ in 0 ..< 5 {
        autoreleasepool {
            for _ in 0 ..< 1000 {
                let image = NSImage(contentsOfFile: filename)
            }
        }
    }
}

If you run this in Instruments, you'll see an allocations graph with 5 small hills (because outer for-loop), like the following:

with autoreleasepool

But if you do it without the autorelease pool, you'll see that peak memory usage is higher:

without autoreleasepool

The autoreleasepool allows you to explicitly manage when autorelease objects are deallocated in Swift, just like you were able to in Objective-C.

Note: When dealing with Swift native objects, you generally will not receive autorelease objects. This is why the presentation mentioned the caveat about only needing this when "working with Objective-C", though I wish Apple was more clear on this point. But if you're dealing with Objective-C objects (including Cocoa classes), they may be autorelease objects, in which case this Swift rendition of the Objective-C @autoreleasepool pattern is still useful.

Top-Master
  • 7,611
  • 5
  • 39
  • 71
Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • If a Swift native object is not an autorelease object, will it get released as soon as the code runs outside of its scope? – Ethan Sep 17 '14 at 04:54
  • Yes, it appears that it does. – Rob Sep 17 '14 at 06:47
  • Does this mean that inside a function, `return aSwiftNativeObject` in Swift is equivalent to `return [anObjcObject autorelease];` in Objective-C? – Ethan Sep 17 '14 at 20:41
  • 2
    On all of these questions, you can write your own class, and have it do a `println` in `deinit`, and it becomes quite easy to verify precisely when objects are deallocated. Or observe it in Instruments. In answer to your question, it appears that Swift objects are returned from functions with +1 retain count (not autorelease objects), and the caller will seamlessly manage ownership from that point (e.g., if and when the returned object falls out of scope, it is immediately deallocated, not placed in an autoreleasepool). – Rob Sep 17 '14 at 20:49
  • if this is the case. why is it that in some cases specially when using UIMapView Kit there are memory leaks? I have not been able to pin down a solution, but I can see the problem. – S.H. Oct 27 '14 at 14:10
  • 3
    @StevenHernandez An autorelease pool has very little to do with leaks. A leak is caused by unreleased object. Autorelease pool, on the other hand, is just a collection of objects for which the release is deferred until the pool is drained. Pools don't control whether something is deallocated or not, but rather merely the timing of such deallocation. Re map view, you can't control what caching it does (uses memory, but not true leak) nor do anything if there was a real leak (and I'm not aware of any significant map view leaks, though historically there have been random, modest leaks in UIKit). – Rob Oct 27 '14 at 14:46
  • I understand and thanks for the complete explanation... So I understood the term incorrectly and assumed both were correlated. – S.H. Oct 27 '14 at 14:56
  • I tried this and my results were not at all the same. I commented out the `autoreleasepool` from the code, but I didn't see any growth. I raised `j` to 1000 and then to 10000 but my results were the same; memory usage is absolutely flat, whether I view it in Instruments or in the Debug pane gauge. So I wonder whether we _ever_ need to use `autoreleasepool` in Swift. – matt Feb 06 '15 at 18:23
  • 3
    @matt Yeah, I saw similar behavior. So I repeated my exercise with `NSImage`/`UIImage` objects and manifested the problem more consistently (and, frankly, this is a more common example of the problem, as peak memory usage is often only problematic when dealing with larger objects; a practical example of this might be a routine resizing a bunch of images). I also reproduced the behavior calling Objective-C code that explicitly created autorelease objects. Don't get me wrong: I think we need autorelease pools in Swift less often than in Objective-C, but it still has a role to play. – Rob Feb 07 '15 at 20:23
  • @Rob My point is that your answer shows code and Instruments graphs as if they go together, but using your code I can't get those graphs. Can you revise so that the code and the graphs reproducibly go together? – matt Feb 08 '15 at 00:11
  • Those graphs _were_ generated by that code sample. But, with the current compiler, I was no longer getting that same graph, so you'll notice that I had already updated the code sample and charts. – Rob Feb 08 '15 at 00:21
  • 1
    I found an example that works! Just call NSBundle's `pathForResource:ofType:` repeatedly. – matt Feb 08 '15 at 02:00
  • 1
    My `pathForResource:ofType:` example no longer works in Xcode 6.3 / Swift 1.2. :) – matt Feb 13 '15 at 20:03
  • you should add this answer as an example under the [arc documentation](https://stackoverflow.com/documentation/ios/4150/arc-automatic-reference-counting#t=201702170158148007432) as an example about autorelease pools – Fonix Feb 17 '17 at 02:24
  • 1
    Uau this works super fine! I have solved many of my memory issues when operating with many and large images at the same time!!! Thx @Rob – sabiland Aug 09 '19 at 09:46
  • 1
    When you get to the pearly gates and the bouncer gives you a problem, just tell him "I left the Swift autorelease answer on StackOverflow". You'll get an immediate pass. – Stickley Sep 14 '19 at 01:47
5

If you would use it in the equivalent Objective-C code, then you would use it in Swift.

will Swift be smart enough to know that the number variable should be released after the first }

Only if Objective-C does. Both operate along the Cocoa memory management rules.

Of course ARC knows that number goes out of scope at the end of that iteration of the loop, and if it retained it, it will release it there. However, that does not tell you whether the object was autoreleased, because -[NSNumber numberWithInt:] may or may not have returned an autoreleased instance. There is no way you can know, because you don't have access to the source of -[NSNumber numberWithInt:].

newacct
  • 119,665
  • 29
  • 163
  • 224
  • 1
    If Swift behaves the same as Objective-C for this, why the presentation mentioned "Working with Objective-C?" specifically? – Ethan Sep 16 '14 at 23:19
  • 12
    @Ethan It would appear that native Swift objects are not autorelease objects, and the `autoreleasepool` construct is entirely unnecessary. But if your Swift code is handling Objective-C objects (including Cocoa objects), those do follow autorelease patterns, and thus the `autoreleasepool` construct becomes useful. – Rob Sep 17 '14 at 03:46
  • I get that "The autoreleasepool allows you to explicitly manage when autorelease objects are deallocated in Swift" but why would I want to? Why doesn't/can't the compiler do it for me? I had to add my own autoreleasepool to keep VM from going through the roof in a tight loop of huge string manipulations. It was obvious to me where it should be added, and it worked perfectly. Why couldn't the compiler do it? Could the compiler be made smarter to do a good job of it? – vonlost Jun 05 '20 at 17:08
0

@autoreleasepool can be used in Objective-C and Swift code to guarantee working with Objective-C code which relies on autorelease

[Under the hood]

yoAlex5
  • 29,217
  • 8
  • 193
  • 205