To restrict access to code blocks,
modules and abstraction is done through access control. Classes, structures and
enumerations can be accessed according to their properties, methods,
initializers and subscripts by access control mechanisms. Constants, variables
and functions in a protocol are restricted and allowed access as global and
local through access control. Access control applied to properties, types and
functions can be referred as 'entities'.
Access control model is based on
modules and source files.
Module is defined as a single unit
of code distribution and can be imported using the keyword 'import'. A source
file is defined as a single source code file with in a module to access
multiple types and functions.
Three different access levels are
provided by Swift language. They are Public, Internal and Private access.
S.No
|
Access Levels & Definition
|
1
|
Public
Enables entities to be processed
with in any source file from their defining module, a source file from
another module that imports the defining module.
|
2
|
Internal
Enables entities to be used
within any source file from their defining module, but not in any source file
outside of that module.
|
3
|
Private
Restricts the use of an entity to
its own defining source file. Private access plays role to hide the
implementation details of a specific code functionality.
|
Syntax
internal
class SomeInternalClass {}
private
class SomePrivateClass {}
public
var somePublicVariable = 0
internal
let someInternalConstant = 0
private
func somePrivateFunction() {}
Some functions may have arguments
declared inside the function without any return values. The following program
declares a and b as arguments to the sum() function. Inside the function itself
the values for arguments a and b are passed by invoking the function call sum()
and its values are printed thereby eliminating return values. To make the
function's return type as private, declare the function's overall access level
with the private modifier.
let a = a + b
let b = a - b
println(a, b)
}
sum(20, 10)
sum(40,10)
sum(24,6)
Result:
(30,
20)
(50,
40)
(30,
24)
Access Control for Enumeration types
public enum Student {
case Name(String)
case Mark(Int,Int,Int)
}
var studDetails = Student.Name("Swift")
var studMarks = Student.Mark(98,97,95)
switch studMarks {
case .Name(let studName):
println("Student
name is: \(studName).")
case .Mark(let Mark1, let Mark2, let Mark3):
println("Student
Marks are: \(Mark1),\(Mark2),\(Mark3).")
default:
println("Nothing")
}
Result:
Student
Marks are: 98,97,95
Enumeration in Swift language
automatically receive the same access level for individual cases of an
enumeration. Consider for example to access the students name and marks secured
in three subjects enumeration name is declared as student and the members
present in enum class are name which belongs to string datatype, marks are
represented as mark1, mark2 and mark3 of datatype Integer. To access either the
student name or marks they have scored. Now, the switch case will print student
name if that case block is executed otherwise it will print the marks secured
by the student. If both condition fails the default block will be executed.
Access Control for SubClasses
Swift allows the user to subclass
any class that can be accessed in the current access context. A subclass cannot
have a higher access level than its superclass. The user is restricted from
writing a public subclass of an internal superclass.
public class cricket {
private func print() {
println("Welcome
to Swift Super Class")
}
}
internal class tennis: cricket {
override internal func print() {
println("Welcome
to Swift Sub Class")
}
}
let cricinstance = cricket()
cricinstance.print()
let tennisinstance = tennis()
tennisinstance.print()
Result:
Welcome
to Swift Super Class
Welcome
to Swift Sub Class
Access Control for Constants, variables,
properties and subscripts
Swift constant, variable, or
property cannot be defined as public than its type. It is not valid to write a
public property with a private type. Similarly, a subscript cannot be more
public than its index or return type.
When a constant, variable,
property, or subscript makes use of a private type, the constant, variable,
property, or subscript must also be marked as private −
private var privateInstance = SomePrivateClass()
Getters and Setters
Getters and setters for constants,
variables, properties, and subscripts automatically receive the same access
level as the constant, variable, property, or subscript they belong to.
class Samplepgm {
private var counter: Int = 0 {
willSet(newTotal) {
println("Total
Counter is: \(newTotal)")
}
didSet{
if counter > oldValue {
println("Newly
Added Counter \(counter - oldValue)")
}
}
}
}
let NewCounter = Samplepgm()
NewCounter.counter = 100
NewCounter.counter = 800
Result:
Total
Counter is: 100
Newly
Added Counter 100
Total
Counter is: 800
Newly
Added Counter 700
Access Control for Initializers and Default
Initializers
Custom initializers can be assigned
an access level less than or equal to the type that they initialize. A required
initializer must have the same access level as the class it belongs to. The
types of an initializer's parameters cannot be more private than the
initializer's own access level.
To declare each and every subclass
of the initialize 'required' keyword needs to be defined before the init()
function.
class classA {
required init() {
var a = 10
println(a)
}
}
class classB: classA {
required init() {
var b = 30
println(b)
}
}
let res = classA()
let print = classB()
Result:
10
30
10
A default initializer has the same
access level as the type it initializes, unless that type is defined as public.
When default initialize is defined as public it is considered internal. When
the user needs a public type to be initializable with a no-argument initializer
in another module, provide explicitly a public no-argument initializer as part
of the type's definition.
Access Control for Protocols
When we define a new protocol to
inherit functionalities from an existing protocol, both has to be declared the
same access levels to inherit the properties of each other. Swift access
control won't allow the users to define a 'public' protocol that inherits from
an 'internal' protocol.
public protocol tcpprotocol {
init(no1: Int)
}
public class mainClass {
var no1: Int // local
storage
init(no1: Int) {
self.no1 = no1 //
initialization
}
}
class subClass: mainClass, tcpprotocol {
var no2: Int
init(no1: Int, no2 : Int) {
self.no2 = no2
super.init(no1:no1)
}
// Requires
only one parameter for convenient method
required override convenience
init(no1: Int) {
self.init(no1:no1, no2:0)
}
}
let res = mainClass(no1: 20)
let print = subClass(no1: 30, no2: 50)
println("res is: \(res.no1)")
println("res is: \(print.no1)")
println("res is: \(print.no2)")
Result:
res
is: 20
res
is: 30
res
is: 50
Access Control for Extensions
Swift does not allow the users to
provide an explicit access level modifier for an extension when the user uses
that extension to add protocol conformance. The default access level for each
protocol requirement implementation within the extension is provided with its
own protocol access level.
Access Control for Generics
Generics allow the user to specify
minimum access levels to access the type constraints on its type parameters.
public struct TOS<T> {
var items = [T]()
private mutating
func push(item: T) {
items.append(item)
}
mutating func pop() -> T {
return items.removeLast()
}
}
var tos = TOS<String>()
tos.push("Swift")
println(tos.items)
tos.push("Generics")
println(tos.items)
tos.push("Type Parameters")
println(tos.items)
tos.push("Naming Type Parameters")
println(tos.items)
let deletetos = tos.pop()
Result:
[Swift]
[Swift,
Generics]
[Swift,
Generics, Type Parameters]
[Swift,
Generics, Type Parameters, Naming Type Parameters]
Access Control for Type Aliases
The user can define type aliases to
treat distinct access control types. Same access level or different access
levels can be defined by the user. When type alias is 'private' its associated
members can be declared as 'private, internal of public type'. When type alias
is public the members cannot be alias as an 'internal' or 'private' name
Any type aliases you define are
treated as distinct types for the purposes of access control. A type alias can
have an access level less than or equal to the access level of the type it
aliases. For example, a private type alias can alias a private, internal, or
public type, but a public type alias cannot alias an internal or private type.
public protocol Container {
typealias ItemType
mutating func append(item: ItemType)
var count: Int { get }
subscript(i: Int) -> ItemType { get }
}
struct Stack<T>: Container {
// original
Stack<T> implementation
var items = [T]()
mutating func push(item: T) {
items.append(item)
}
mutating func pop() -> T {
return items.removeLast()
}
//
conformance to the Container protocol
mutating func append(item: T) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> T {
return items[i]
}
}
func allItemsMatch<
C1: Container, C2: Container
where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
(someContainer: C1,
anotherContainer: C2) -> Bool {
// check
that both containers contain the same number of items
if
someContainer.count != anotherContainer.count {
return false
}
// check
each pair of items to see if they are equivalent
for i in 0..<someContainer.count {
if
someContainer[i] != anotherContainer[i] {
return false
}
}
// all items
match, so return true
return true
}
var tos = Stack<String>()
tos.push("Swift")
println(tos.items)
tos.push("Generics")
println(tos.items)
tos.push("Where Clause")
println(tos.items)
var eos = ["Swift", "Generics", "Where
Clause"]
println(eos)
Result:
[Swift]
[Swift,
Generics]
[Swift,
Generics, Where Clause]
[Swift,
Generics, Where Clause]