Swift is using Automatic Reference Counting (ARC) in memory management. Although callings of retain, release and autorelease manually are forbidden in ARC way, they actually are added automatically by the compiler and called as they were there. retain and release are quite straightforward. They will increase and reduce the reference count respectively. autorelease is quite special at this level. The receiver will be inserted into a pre-created auto release pool. When the pool receives a drain method, the reference count of all objects in the pool will be reduced by the times they appear in the pool.

In an iOS app, the main function is running in an auto release pool. A drain operation of that pool will happen at the end of every main run loop. This kind of delay-release is necessary in development, sometimes we will want a variable lives longer than its scope (such as a callee function), so we can keep using it later.

The syntax of creating an auto release pool in Objective-C is very easy. Use @autoreleasepool will do the trick. If you create a new app project in Objective-C, you may find there is an auto release pool in main.m, which is we just mentioned:

int main(int argc, char *argv[]) {
    @autoreleasepool {
        int retVal = UIApplicationMain(
            argc,
            argv,
            nil,
            NSStringFromClass([AppDelegate class]));
        return retVal;
    }
}

Furthermore, the @autoreleasepool is a compiler directive. It will be expanded to something like NSAutoreleasePool, with a drain calling at the end.

In Swift project, we have @UIApplicationMain. There is no need to add neither main file nor main method. Even if we create our own main.swift as an entry point of the app, there is no need to add anything related to auto release pool. This boilerplate code is completed avoided, which is cool.

But there is one situation we do need to autorelease, that is we create a lot of objects in a method scope and want to release them sooner. It is extremely useful when these objects turn to a pressure on memory. In Swift 1.0, we could use a factory method like this:

func loadBigData() {
    if let path = NSBundle.mainBundle()
        .pathForResource("big", ofType: "jpg") {

        for i in 1...10000 {
            let data = NSData.dataWithContentsOfFile(
                path, options: nil, error: nil)

            NSThread.sleepForTimeInterval(0.5)
        }        
    }
}

Different from an init method, dataWithContentsOfFile is returning autorelease object. Since in the loop scope, there is no chance for them to release. When the amount is big enough, it will become easy to crash the app. We can inspect the memory alloc in Instruments:

Obviously, we would not want to see this. A better way is adding an auto release pool into it, to drain the auto release pool at some point in the loop. In fact, we can use autoreleasepool in Swift -- although it is a little different from Objective-C in syntax. It now becomes a function accepting a closure as parameter, instead of a keyword.

func autoreleasepool(code: () -> ())

Make use of trailing closure in Swift, we can use auto release pool like this:

func loadBigData() {
    if let path = NSBundle.mainBundle()
        .pathForResource("big", ofType: "jpg") {

        for i in 1...10000 {
            autoreleasepool {
                let data = NSData.dataWithContentsOfFile(
                    path, options: nil, error: nil)

                NSThread.sleepForTimeInterval(0.5)
            }
        }        
    }
}    

After doing that, the worry about memory could go away.

We created an auto release pool every loop. While this could ensure the footprint of memory keeps minimum, it might cause a potential overhead when releasing the small pieces of memory. A better solution would be divide the huge loop into smaller parts and create auto release pool for them. For example, we can create and drain a pool when the program goes every 10 loops. It will contribute to performance.

For this specific example, we do not need to add auto release pool indeed. In Swift 1.1, with the added feature of failable initializers, class factory methods like dataWithContentsOfFile are completely removed. Apple suggests to always use failable initializers instead:

let data = NSData(contentsOfFile: path)

Since data will be a strong reference instead of an autorelease object, there is no auto releasing concern in the code.

But as an optimization option, it is worth to know when and how to use auto release pool in Swift as well.