Updated December 21 for Xcode 6.1.1
The Swift feature of Access Control is really important from a software architecture perspective, because it allows us to properly implement encapsulation. Without the ability to hide members and methods of classes, it’s very easy to accidentally (or not) reach in to classes and mess with internals that were not designed to be directly modified.
Swift offers three levels of access control: public, private, and internal.
public makes the entities visible anywhere within the module, or from other modules (as long as the module is imported)
internal makes the entities visible only within the same module. This is the default behavior in Swift.
private makes the entities visible only within the same source file.
To demonstrate Swift’s new access controls, let’s build a small math class for Swift. For now, it’ll be really simple. It’s a class that has two properties of type Double, and has a single computed property named sum. If you want to follow along, just create a single-view template project and add this in to an otherwise empty swift file called Math.swift
import Foundation class QMath { var num1: Double? var num2: Double? var sum: Double { return num1! + num2! } init(_ num1: Double, _ num2: Double) { self.num1 = num1 self.num2 = num2 } }
The class QMath has a constructor that takes two parameters, num1 and num2 of type Double. If you haven’t seen the underscores before, those are the external parameter names, which we’ve set to not be specified by using the underscore. If we instantiate a QMath instance in another class we can get the sum property and confirm it works as expected.
If you’re following along, you insert this in to your applicationdidFinishLaunchingWithOptions: method inside of AppDelegate.swift
var m = QMath(4, 50) println(m.sum)
54.0
You’ll notice that in our sum getter, we implicitly unwrap num1 and num2 using the exclamation mark (!). Although they’re both optionals, we can make this assumption if we know the init(,) method we’ve provided is called, because the arguments to that method are not optional and will definitely be set upon initialization.
Except one minor problem:
We could actually set either of those values to be nil.
var m = QMath(4, 50) m.num1 = nil println(m.sum)
This code compiles just fine, num1 is Optional and can be set to nil, not an issue. However, calling the sum getter now implicitly unwraps a nil optional. If you run this code you’ll see the following error:
fatal error: unexpectedly found nil while unwrapping an Optional value
We could simply set the num1 and num2 properties to not be optional, which would require we have a default value such as 0. But, an better approach that allows us to avoid the unnecessary initial value is to simply disallow modifications to these internal variables. We want this class to be a black box, where num1 and num2 can’t directly be modified.
So, to solve our above mentioned issue, we can make the two number properties private.
private var num1: Double? private var num2: Double?
Attempting to build the app again now produces an error on the line we used to set num1 to nil.
m.num1 = nil
'QMath' does not have a member named 'num1'
Our external reference to the num1 property is no longer valid, it has no visibility to num1 and therefore this line of code is an error. There’s only one thing to do now, remove this line and start using the class as it was designed to be used! Mission accomplished!
If you want to dive deeper and tinker with Swift, it’s a good idea to read my post on Running Swift Scripts From The Command Line. When you’re ready to get serious make sure to also learn about my upcoming Swift eBook and video tutorial series.
Warning: Incoming opinion
Good software design principles suggest everything should be private by default, and entities should be exposed deliberately on an as-needed basis. This makes it easier to write more modular code and leads to cleaner programming interfaces. Disagree? Yell at me about it on Twitter.