08

swift_down_595x126

I am using Swift for several months now, and really like the language. While Xcode support is not so great, the language significantly improves my daily coding sessions. However, there are aspects of Swift that are not really clear to me. One of them is objects initialization issue which quietly causing memory leaks.

What’s wrong with init?

Let’s assume that we have MyObject class, which objects does nothing except logging to the console whenever they are initialized or de-initialized:

class MyObject {
    init() {
        NSLog("MyObject init")
    }
    deinit {
        NSLog("MyObject deinit")
    }
}

We also have custom view controller, that extends UIViewController, and holds MyObject instance using constant reference (let):

class ViewController: UIViewController {
    let object = MyObject()
}

Nothing complicated so far, everything is clear. So, imagine you want to initialize a ViewController object:

let myViewController = ViewController()

Looks good? Well, it’s not. You just created a memory leak, which can be confirmed by profiling the app using Xcode’s Instruments. To better understand what is going on, you can change your code, so ViewController object will be initialized and immediately deallocated:

var myViewController: ViewController? = ViewController()
myViewController = nil

Now, check out the console output:

MyObject init
MyObject init
MyObject deinit

Yes, that’s right. Calling ViewController() is causing MyObject instance to be initialized twice, in fact there are two instances of MyObject. One of them is hold by object property in ViewController, another one – just leaked and probably will never be deallocated.

How is that even possible?

My guess is that UIViewController init method could be implemented like this:

- (id)init {
    self = [super init];
    if (self) {
        self = [[self.class alloc] initWithNibName:nil bundle:nil];
    }
    return self;
}

While this should work in Objective-C world, it’s problematic in Swift. There is no such thing like automatic property initialization in Objective-C, or default property values. However, in Swift properties are initialized before the object that defines them is initialized, automatically.

That’s only my guess, we can’t be sure if that’s really a reason of the issue. For sure, every Swift developer should pay extra attention when initializing Foundation, UIKit, AppKit or other pre-Swift frameworks. I can confirm that this issue can be reproduced not only with UIViewController, but also UIButton and many other UIKit classes.

Avoiding such nonsense

Thankfully, there is very easy way no avoid such memory leaks. You should always choose the correct initializer for given class.

You can call init without parameters on UIViewController because (like many others) it extends from NSObject. But when you look inside documentation, you will see that the UIViewController initializer is initWithNibName:bundle:.

It’s a pity Swift can’t warn us when we are trying to init UIViewController with init(), as it looks obviously wrong and you should never do that. Perhaps it will be improved in future releases.

Tested under Xcode 6.1.1 and Xcode 6.2 beta