Levels of Access Control

There are five levels of access control, from highest(least restrictive) to lowest(most restrictive) are open, public, internal, file-private, private.

I will try to use some simple example codes to demonstrate these access levels, and I would like to start from lowest to highest. In this part, I will cover the first 3 lower levels: private, fileprivate and internal.

Private Access

Let’s start with declaring a class named Somebody.

class Somebody {

private var salary: Int = 100000

func gotPromotion(of raise: Int) {

salary += raise

}

}

People usually regard their salary as top secrets to others, so we wrote private var salary , this means it can only be used within this Somebody class (enclosing declaration). We also have func gotPromotion(of raise: Int) for promotion and it will increase the salary with raise amount. We can access the salary variable in that function without runtime error because the function is defined in the enclosing declaration same as salary variable.

let zoe = Somebody() // salary is 100000

zoe.gotPromotion(of: 3000) // salary is 103000

print(zoe.salary) // runtime error ❌❌❌

Above we created a constant instance of Somebody class named zoe and she got promoted with a raise of 3000(🤑) right away. However, when we try to get her salary value, there will be a runtime error shows. ’salary’ is inaccessible due to ‘private’ protection level . This is because where we declared zoe is not within the same enclosing declaration with private var salary , that is not allowed under private access protection.

From Swift 4.0, if an extension is in the same source file of a declaration, private values can also be accessed within that extension. Let’s try to add an extension to Somebody class in the same file.

extension Somebody {

func gotBonus(of bonus:Int){

salary += bonus

}

}

Now combine everything and give zoe a surprising bonus.

class Somebody {

private var salary: Int = 100000

func gotPromotion(of raise: Int) {

salary += raise

}

} extension Somebody {

func gotBonus(of bonus:Int){

salary += bonus

}

} let zoe = Somebody() // salary is 100000

zoe.gotPromotion(of: 3000) // salary is 103000

zoe.gotBonus(of: 2000) // salary is 105000

It works like a charm 🎉🎉🎉

File-private Access

As the name implies, file-private means it can only be accessed within its own defining source file. We can now go-ahead to add a new variable and function in Somebody class to try this out.

Compare to salary, people may be less sensitive about what’s their title at work. We add fileprivate var jobTitle and another func changeJobTitle(to: String) for changing job title value.

class Somebody {

private var salary: Int = 100000



fileprivate var jobTitle:String

= "iOS Developer"



func gotPromotion(of raise: Int) {

salary += raise

}



func changeJobTitle(to newJobTitle:String) {

jobTitle = newJobTitle

}

} let zoe= Somebody()

// jobTitle is iOS Developer

zoe.changeJobTitle(to:"Senior iOS Developer")

// jobTitle is Senior iOS Developer

zoe.gotPromotion(of:100000)

// salary is 200000

print(zoe.jobTitle)

// Prints "Senior iOS Developer"

Different to private salary value, when we try to print out zoe’s jobTitle value after changing it to “Senior iOS Developer”, there won’t be any runtime error. However, if we declare another instance of Somebody class in other source files and try to access jobTitle, Xcode will show up a runtime error saying ‘jobTitle’ is inaccessible due to ‘fileprivate’ protection level .

Internal Access

The default access level is internal access. Without specifying an explicit access level when defined, entities will have access level of internal by default, which makes them being usable within all the source files from their defining module.

Compare to the previous two access levels, private and fileprivate, which are both source-file-wise, internal level is module-wise.

In fact, we already used the internal access level in previous Somebody example. class Somebody doesn’t have explicit access level been defined so it automatically has internal access. Let’s say Somebody class is defined in the file Somebody.swift , if now we add a new file called TeamMembers.swift in the same project(module), we won’t have any problem to create instances of Somebody class in this source file.

// TeamMembers.swift class TeamMembers {

let a = Somebody()

let b = Somebody()

let c = Somebody()



func promote(_ member: Somebody, to jobTitle: String, with raise:Int) {

member.changeJobTitle(to: jobTitle)

member.gotPromotion(of: raise)

}

} let members = TeamMembers()

members.promote(members.a, to: "iOS Lead", with: 1000)

print(members.a.jobTitle) //prints "iOS Lead"