Swift 3 Access Controls

Swift 3 has brought us some interesting access control changes. The differences between open and public or private and fileprivate take some getting used to. Luckily unless you are writing a framework the new rules are simple. Here is what you need to know.

Note: Swift 4 has changed the scope of private access reducing the need to use fileprivate for extension access. See Swift 4 access levels for details.

The Five Access Levels of Swift 3

Swift 3 has five access levels that control from which source file or module you can access something. In order from most open to most restricted:

Note that Objective-C classes and methods are now imported as open.

Don’t Panic

It is worth remembering that an application is a module and that internal access is the default. This means application code you write is accessible from all source files in the application by default.

Unless you are writing a framework you probably only need to think about access levels when you want to restrict access to a single source file using fileprivate or private.

Using fileprivate and private

Let’s look at some examples where we might want to use fileprivate and private. Suppose I have a view controller that has a property which I do not want accessed outside of the source file. In Swift 2 I would declare it as private and move on:

class RootViewController: UIViewController {
  private var someFlag = false

Unfortunately, using Swift 3, if I now try to access this property from a class extension, in the same source file, I hit a problem:

extension RootViewController: MyGreatDelegate {
  func doSomething {
    if someFlag {
      // do the thing

// Use of unresolved identifier 'someFlag'

The problem is that the private access level restricts access to the property to the enclosing class declaration. The extension is not allowed access even though it is in the same source file. The solution is to switch the access level to fileprivate:

class RootViewController: UIViewController {
  fileprivate var someFlag = false

Another example using private in extensions for methods that you do not want accessed outside of the extension. For example, helper methods for a delegate:

extension RootViewController: UITextFieldDelegate {
  func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    handle(text: textField.text)
    return true

  // Not accessible outside of this extension
  private func handle(text: String?) {
    // do something

Other Hints and Tips

Getters and Setters

You can give a setter lower access than its getter to limit the read-write access.

class MyDataSource {
  // property is read-only outside of this class definition
  private(set) var someFlag = false

  // ...

By default the property getter and setter in this example would have internal access. Making the setter have a private access level means we can only set it within the class definition. We cannot set it from another source file or from a class extension in the same source file. If we wanted to be able to set the property from an extension we would need to give the setter fileprivate access:

  fileprivate(set) var someFlag = false

Unit Test Targets

A unit test target is its own module so does not have access to any types or properties in the application module that are by default internal. You give your tests internal access by importing with the @testable attribute:

import XCTest
@testable import MyDataSource
class MyDataSourceTests: XCTestCase {
  // func testSomething() {...}

Final - Preventing Overrides

The final keyword is not an access level but you can add it to any of the access levels (apart from open) to prevent subclassing or overriding. There is a potential performance improvement from this as the compiler can avoid dynamic dispatch though you can allow the compiler to infer this if you use Whole Module Optimization.

Further Reading

Never Miss A Post

Sign up to get my iOS posts and news direct to your inbox and I'll also send you a PDF of my WWDC Viewing Guide

    Unsubscribe at any time. See privacy policy.

    Archives Categories