Swift access control
Access control can limit the access level of code in other source files or modules to your code.
You can explicitly set access levels for individual types (classes, structures, enumerations), or for properties, functions, initialization methods, basic types, subscript indexes, etc. of these types.
The protocol can also be limited to a certain scope, including global constants, variables and functions in the protocol.
Access control is based on modules and source files.
Module refers to a Framework or Application that is built and published as an independent unit. In Swift, a module can import another module using the import keyword.
The source file is a single source code file, which usually belongs to a module. The source file can contain the definition of multiple classes and functions.
Swift provides three different access levels for entities in code: public, internal, and private.
Access level | Definition |
---|---|
Public | You can access source files in your own module Any entity in the source file, others can also access all entities in the source file by introducing this module. |
Internal | : You can access any entity in the source file in your own module, but others cannot access the entities in the source file in the module. |
Private | Entities that can only be used in the current source file are called private entities. |
Public is the highest access level, and private is the lowest access level.
Syntax
Declare the access level of an entity through the modifiers public, internal, and private:
public class SomePublicClass {} internal class SomeInternalClass {} private class SomePrivateClass {} public var somePublicVariable = 0 internal let someInternalConstant = 0 private func somePrivateFunction() {}
Unless otherwise specified, entities use the default access level internal .
Function type access permissions
The access level of a function needs to be derived based on the access level of the parameter type and return type of the function.
The following example defines a global function named someFunction and does not explicitly declare its access level.
func someFunction() -> (SomeInternalClass, SomePrivateClass) { // 函数实现 }
The access level of one of the classes in the function, SomeInternalClass, is internal, and the access level of the other, SomePrivateClass, is private. So according to the principle of tuple access level, the access level of this tuple 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) { // 函数实现 }
Declare the function as public or internal, or use the default access level internal. Incorrect.
Enumeration type access permissions
The access level of the members in the enumeration is inherited from the enumeration. You cannot declare different access levels separately for the members in the enumeration.
Example
For example, in the following example, the enumeration Student is explicitly declared as public level, then the access level of its members Name and Mark are 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 execution output of the above program is:
学生成绩: 98,97,95
Subclass access rights
The access level of a subclass must not be higher than the access level of the parent class. For example, if the access level of the parent class is internal, the access level of the subclass cannot be declared 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 execution output of the above program is:
超类 子类
Constant, variable, attribute, subscript access rights
Constant, variable, and attribute cannot have more than their Type higher access level.
For example, you define a public-level attribute, but its type is private-level, which is not allowed by the compiler.
Similarly, a subscript cannot have a higher access level than the index type or return type.
If the definition type of constants, variables, properties, and subscript indexes is private level, then they must explicitly declare that the access level is private:
private var privateInstance = SomePrivateClass()
Getter and Setter access Permissions
The access level of getters and setters of constants, variables, properties, and subscript indexes is inherited from the access level of the members to which they belong.
The access level of the Setter can be lower than the access level of the corresponding Getter, so that the read and write permissions of variables, properties or subscript indexes can be controlled.
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 execution output of the above program is:
计数器: 100 新增加数量 100 计数器: 800 新增加数量 700
Constructor and default constructor access rights
Initialization
We can customize The initialization method declares an access level, but it should not be higher than the access level of the class to which it belongs. The exception is required constructors, whose access level must be the same as that of the class to which they belong.
Like function or method parameters, the access level of initialization method parameters cannot be lower than the access level of the initialization method.
Default initialization method
Swift provides a default no-parameter initialization method for structures and classes, which is used to provide assignment operations for all 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 it belongs to.
Example
Use the required keyword before the init() method of each subclass to declare access permissions.
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 execution output of the above program is:
10 30 10
Protocol access rights
If you want to explicitly declare a protocol Access level, then one thing to note is that you need to ensure that the protocol is only used within the scope of the access level you declare.
If you define a protocol with public access level, then the necessary functions provided by the protocol will also have public access level. This is different from other types, such as other types with public access level, whose members have access level internal.
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 execution output of the above program is:
res is: 20 res is: 30 res is: 50
Extended access rights
You can perform operations on classes, structures, and enumerations when conditions permit. Extension. Extension members should have the same access level as the original class members. For example, if you extend a public type, the new members you add should have the same default internal access level as the original members.
Alternatively, you can explicitly declare the access level of the extension (such as using a private extension) to declare a new default access level for all members within the extension. This new default access level can still be overridden by the access levels declared by individual members.
Generic access rights
The access level of a generic type or generic function is the lowest access level among the generic type, the function itself, and the generic 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") print(tos.items) tos.push("泛型") print(tos.items) tos.push("类型参数") print(tos.items) tos.push("类型参数名") print(tos.items) let deletetos = tos.pop()
The execution output of the above program is:
["Swift"] ["Swift", "泛型"] ["Swift", "泛型", "类型参数"] ["Swift", "泛型", "类型参数", "类型参数名"]
Type alias
Any type alias you define will be treated as a different type for easy access control. The access level of a type alias cannot be higher than the access level of the original type.
For example, a private-level type alias can be set to a public, internal, or private type, but a public-level type alias can only be set to a public-level type, not to Internal or private level types.
Note: This rule also applies to aliasing related types to satisfy protocol conformance.
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 above program execution output result is:
["Swift"] ["Swift", "泛型"] ["Swift", "泛型", "Where 语句"] ["Swift", "泛型", "Where 语句"]