Swift access control
Access control can limit the level of access to your code by code in other source files or modules.
You can explicitly set access levels for individual types (classes, structures, enumerations), or you can set access levels for properties, functions, initialization methods, basic types, subsumed indexes, and so on.
Protocols can also be used to a limited extent, including global constants, variables, and functions in the protocol.
Access control is based on modules and source files.
Modules refer to Framework or Application built and published in separate units. One module in Swift can use the sport keyword to introduce another module.
A source file is a single source file that typically belongs to a module that can contain the definition of multiple classes and functions.
Swift provides three different levels of access to entities in your code: public, internal, private.
The access level | Defined |
---|---|
Public | You can access any entity in the source file in your own module, and others can access all entities in the source file by introducing the module. |
Internal | : You can access any entity in the source file in your own module, but others cannot access entities in the source file in that module. |
Private | An entity, called a private entity, that can only be used in the current source file. |
Public is the highest level of access and private is the lowest level of access.
Grammar
The access level of the entity is declared by the modifier public, internal, private:
public class SomePublicClass {} internal class SomeInternalClass {} private class SomePrivateClass {} public var somePublicVariable = 0 internal let someInternalConstant = 0 private func somePrivateFunction() {}
Entities use the default access level internal unless there are special instructions.
Function type access
The access level of a function needs to be derived based on the parameter type of the function and the access level of the return type.
The following example defines a global function called homeFunction and does not explicitly state its access level.
func someFunction() -> (SomeInternalClass, SomePrivateClass) { // 函数实现 }
One of the classes in the function, SomeInternalClass, has an access level of internal, and the other, SomePrivateClass, has an access level of private. So according to the principle of the metadata access level, the metadata access level is private.
Because the access level of the function return type is private, you must use the private modifier to explicitly declare the function:private func someFunction() -> (SomeInternalClass, SomePrivateClass) { // 函数实现 }
It would be wrong to state the function as public or internal, or to use the default access level internal.
Enumere type access
The access level of a member in an enumerity is inherited from that enumerity, and you cannot individually state a different access level for a member in an enumerity.
Instance
For example, in the following example, enumeraling Student is explicitly stated as a public level, and its members Name, Mark's access level is also public:
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): print("学生名: \(studName).") case .Mark(let Mark1, let Mark2, let Mark3): print("学生成绩: \(Mark1),\(Mark2),\(Mark3)") }
The output of the above program execution is:
学生成绩: 98,97,95
Sub-class access
The access level of the child class must not be higher than the access level of the parent class. F or example, the access level of the parent class is internal, and the access level of the child class cannot be stated as public.
public class SuperClass { private func show() { print("超类") } } // 访问级别不能低于超类 internal > public internal class SubClass: SuperClass { override internal func show() { print("子类") } } let sup = SuperClass() sup.show() let sub = SubClass() sub.show()
The output of the above program execution is:
超类 子类
Constants, variables, properties, underseed access
Constants, variables, and properties cannot have a higher level of access than their types.
For example, you define a public-level property, but its type is private-level, which the compiler does not allow.
Similarly, the underseed cannot have a higher level of access than the index type or return type.
If the defined types of constants, variables, properties, and underlying indexes are private levels, they must explicitly state that the access level is private:
private var privateInstance = SomePrivateClass()
Getter and Setter access
The access levels for constants, variables, properties, underseed indexes for Getters and Setters are inherited from the access levels of the members to which they belong.
Setter's access level can be lower than the corresponding Getter's, which allows it to control read and write permissions for variables, properties, or substations.
class Samplepgm { private var counter: Int = 0{ willSet(newTotal){ print("计数器: \(newTotal)") } didSet{ if counter > oldValue { print("新增加数量 \(counter - oldValue)") } } } } let NewCounter = Samplepgm() NewCounter.counter = 100 NewCounter.counter = 800
The output of the above program execution is:
计数器: 100 新增加数量 100 计数器: 800 新增加数量 700
Constructor and default constructor access
Initialization
We can state the access level to the custom initialization method, but not higher than the access level of the class to which it belongs. T he necessary constructor exception, however, must have the same level of access as the class it belongs to.
Like function or method parameters, the access level of the initialized method parameter cannot be lower than the access level of the initialized method.
The default initialization method
Swift provides a default non-participating initialization method for structures and classes to assign all of their properties, but does not give specific values.
The access level of the default initialization method is the same as the access level of the type to which it belongs.
Instance
Claim access using the required keyword before the init() method of each sub-class.
class classA { required init() { var a = 10 print(a) } } class classB: classA { required init() { var b = 30 print(b) } } let res = classA() let show = classB()
The output of the above program execution is:
10 30 10
Protocol access
If you want to explicitly state the access level for an agreement, it is important to note that you want to ensure that the protocol is used only in the access level scope that you affirm.
If you define a protocol at the public access level, the necessary functions to implement the protocol are also the public access level. This is different from other types, such as other types of public access levels, where members have internal access levels.
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 show = SubClass(no1: 30, no2: 50) print("res is: \(res.no1)") print("res is: \(show.no1)") print("res is: \(show.no2)")
The output of the above program execution is:
res is: 20 res is: 30 res is: 50
Extend access
You can extend classes, structures, and enumerations as conditions permit. E xtended members should have access levels consistent with the original class members. F or example, if you extend a common type, your new member should have the same default internal access level as the original member.
Alternatively, you can explicitly state the extended access level, such as using the private extension, to give all members of the extension a new default access level. This new default access level can still be overwritten by the access level stated by individual members.
Generic access
The access level of a generic type or generic function is the lowest of the generic type, the function itself, and the generic type parameter.
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") print(tos.items) tos.push("泛型") print(tos.items) tos.push("类型参数") print(tos.items) tos.push("类型参数名") print(tos.items) let deletetos = tos.pop()
The output of the above program execution is:
["Swift"] ["Swift", "泛型"] ["Swift", "泛型", "类型参数"] ["Swift", "泛型", "类型参数", "类型参数名"]
The type alias
Any type alias you define is treated as a different type for access control. The access level of a type alias must not be higher than that of the original type.
For example, a private-level type alias can be set to a public, internal, private type, but a public-level type alias can only be set to a public-level type, not an internal or private-level type.
Note: This rule also applies if the relevant type is aliased to satisfy protocol consistency.
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") print(tos.items) tos.push("泛型") print(tos.items) tos.push("Where 语句") print(tos.items) var eos = ["Swift", "泛型", "Where 语句"] print(eos)
The output of the above program execution is:
["Swift"] ["Swift", "泛型"] ["Swift", "泛型", "Where 语句"] ["Swift", "泛型", "Where 语句"]