When access levels were first introduced in Swift, there was some confusion and criticism about them. While developers were excited about the addition of access control to the Swift programming language, the behavior of the private keyword was different from that of other programming languages.

This has changed in Swift 3 by the addition of another keyword for private access control, fileprivate. The difference is subtle but easy to understand.

Before Swift 3

Before the introduction of Swift 3, the private keyword limited the use of entities (classes, structures, enumerations, ...) to the source file in which they were defined. Take a look at the example below.

import UIKit

class NotesViewController: UIViewController {

    private var dataSource = [String]()

}

extension NotesViewController: UITableViewDataSource {

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return dataSource.count
    }

    ...

}

We declare a UIViewController subclass, NotesViewController, with a private property, dataSource, of type [String]. In the same source file, we create an extension for the NotesViewController class to conform it to the UITableViewDataSource protocol. What is interesting is that we can access the dataSource property in the extension even though the property is declared private.

Swift 3

If we port the above code snippet to Swift 3, the compiler throws an error. It tells us that the dataSource property is an unresolved identifier. In other words, by declaring the dataSource property as private, it is not accessible in the extension.

import UIKit

class NotesViewController: UIViewController {

    private var dataSource = [String]()

}

extension NotesViewController: UITableViewDataSource {

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return dataSource.count
    }

    ...

}

Use of Unresolved Identifier

There's Private and Private

Swift 3 introduces the fileprivate keyword that replaces the private keyword. You can try this out by marking the dataSource property as fileprivate instead of private.

import UIKit

class NotesViewController: UIViewController {

    fileprivate var dataSource = [String]()

}

extension NotesViewController: UITableViewDataSource {

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return dataSource.count
    }

    ...

}

As the name implies, the fileprivate keyword limits access to the entity to the source file it is declared in. We can verify this by moving the extension for the NotesViewController class to a separate file. This results in the same error we encountered earlier.

import UIKit

extension NotesViewController: UITableViewDataSource {

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return dataSource.count
    }

}

Use of Unresolved Identifier

What About Private

You can still use the private keyword for access control. The Swift team has listened to the feedback of the community and, as a result, the meaning of the private keyword is now similar to that in many other programming languages. An entity that is declared private can only be accessed within the lexical scope it is declared in. Euh. What?

To better understand this, we need to revisit the previous example. The extension for the NotesViewController class was unable to access the dataSource property if we marked it as private, even if we added the extension to the same source file in which the NotesViewController class was declared. Why is that?

The dataSource property is only accessible from within the NotesViewController class. As a rule of thumb, when using the private keyword, the entity is only accessible within the set of curly braces it is declared in.

Is This Better?

While private and fileprivate may be confusing at first, I am very glad that private now has a clearer, more intuitive meaning. The original implementation of the private keyword confused many developers, especially those coming from other programming languages. By renaming private to fileprivate, this is no longer the case. The name clearly indicates that an entity is private to a particular (source) file.

Even though the Swift evolution proposal mentions that this change enables developers to spread the implementation of entities across multiple files, this doesn't seem to be possible at the moment. My hope is that this changes in the future.