Swift: Weak Vars
TL;DR : WeakVars.playground
Swift has Automatic Reference Counting (ARC) baked into the language. It is supported by LLVM and Xcode warns about any misuse of variables and properties as quickly it can evaluate your code. The way Swift works and works so well has been a long time in the works.
Back in the year 2000 Chris Lattner started working on LLVM as a set of compiler tools. It is now used for a variety of languages and build systems including C, Objective-C and Google Chrome and Android. Clang is the frontend for the LLVM tools which has been used as a replacement for the long time standard gcc which is common on Linux systems. Now systems like FreeBSD and Xcode use LLVM as the default. Years ago when Xcode was still using gcc to compile Mac and iOS projects the IDE lacked features that developers who worked with Java or C# had come to know and expect from tools like Eclipse and Visual Studio. Was was missing from gcc was a static analyzer which could be run as the developer typed code into the editor which is how Eclipse and Visual Studio provided that functionality.
Previously in order to identify syntax warnings and errors with a project Xcode had to build the entire project and look at the output from gcc before telling the developer about warnings and errors. With the Clang Static Analyzer it is now possible for Xcode to evaluate code immediately as the developer types code bringing a modern IDE experience to Xcode. We now have what those Java and .NET developers have had for many years. Life is good.
Before we had a powerful static analyzer for Objective-C developers had to carefully manage memory with references. This was a time before Automatic Reference Counting (ARC). This was the dark ages. I lived through that time. I had to carefully use “alloc” to claim memory for an instance of an object and later either use “release” or carefully use “autorelease” to allow the reference count to drop to zero so the Objective-C runtime could free the memory that was used for that reference. Handling released incorrectly was the cause of many memory leaks and crashes. If an app did not release references it would use up too much memory and crash. If an app released a reference which was still being used and it was then used it would crash the app. Apple found that a good number of these crashed happened as a result of calling viewDidUnload so that Apple stopped calling that method and advised developers to stop using it. I spent a lot of time reading and re-reading a lot of code to ensure my app would not experience these crashes. Now with Clang and LLVM I can let Xcode tell me immediately when there is a problem so I can fix it before it goes any further.
With Swift, the language is set up to use ARC out of the box. You cannot even get the code to compile for conditions which might be allowed in Objective-C because these conditions were anticipated and bad scenarios are now prevented. You do not even have to use “alloc” to reserve memory for an object. It works a lot more like JavaScript but under the hood it is a lot like C or Objective-C but the language we use is much more pleasant.
One problem with references is that if the count cannot reach zero as a result of a circular dependency there will be a memory leak which could result in a crash. A circular reference typically happens when 2 objects refer to each other. If the properties used for these properties are strong the reference count will be at two and may not drop to zero so the memory it uses will not be released.
Preventing circular references can be done with weak vars in Swift. This means the reference is not counted as a strong reference which is what controls when resources are released. Only strong references increase and decrease the count. In the playground named SwiftWeakVars.playground I created classed named Person and Apartment. A person has a property for their apartment and an apartment has a property for a tenant. This sets up a circular reference and to prevent the problem we want to avoid I made both of these properties weak. For this simple example in a Playground it works well enough for this example. This topic will be explored in more detail late with unowned vars.
Weak References for Outlets
In a more common scenario I created an iOS project which sets up a table view with a list of names. A label in each table cell is used to display each name. Since the label is owned by it’s superview it is not necessary to also have a strong reference to it. Each reference from superview from the label to the view controller’s view is strong. You let the scene get instantiated from the Storyboard which attaches outlets defined in the view controller so a series of strong references for every view is made. By default Xcode will create a forced unwrapped optional for the outlet when you create an outlet from the Storyboard. Many developers prefer to make these outlets as optionals instead. I am one of those developers. So in this example I made the reference for the table view outlet weak so only the owner of the table view has a strong reference to it. I can still use this weak reference to work with the table view.
The table view also has it’s own outlets for the delegate and dataSource properties. These are also weak outlets. The view controller which is referencing the table view through it’s superview does not need the table view to hold onto strong references to itself which would be a circular reference. When the view controller is released it should not need these references as the owner of the table view is also being released. The SwiftWeakVars project shows how weak vars are used in this scenario.
Bonus Example
In addition to making the outlet for the table view weak I also created a custom class for the table cell. It is declared below the view controller’s class as an internal class so that it can define an outlet for the label that is used. Often when a custom class is created a separate source file is used. I feel that creating new files for table cells clutters up a project with very small source files mostly used for outlets. If it is just used to create outlets I feel like making it an internal class will be sufficient. It also has an outlet which is declared as an optional so it could be nil and the data source function that uses can handle it safely like an optional.
Next: Strong Properties
GitHub Gist