Swift访问控制
限制访问代码块,模块和抽象通过访问控制来完成。类,结构和枚举可以根据自己的属性,方法,初始化函数和下标来通过访问控制机制进行访问。常量,变量和函数的协议限制,并允许通过访问控制来访问全局和局部变量。应用于属性,类型及函数的访问控制可以被称为“实体”。
访问控制模型是基于模块和源文件的。
模块定义为代码分配一个单独的单元,并且可以使用import 关键字导入。源文件被定义为一个单一的源代码文件,模块可访问多种类型和函数。
三种不同的访问级别是由 Swift 语言提供。它们分别是 Public, Internal 和 Private 访问。
方法级别 | 定义 |
Public | 启用实体可以以任何源文件从它们的定义模块处理,导入已定义模块到另一个模块的源文件中。 |
Internal | 从它们定义模块启用实体被包含在任何的源文件,但不是在模块的外部的任何源文件。 |
Private | 限制使用一个实体的自身限定源文件。private访问扮演的角色是隐藏一个特定代码功能的实现细节。 |
语法
public class SomePublicClass {} internal class SomeInternalClass {} private class SomePrivateClass {} public var somePublicVariable = 0 internal let someInternalConstant = 0 private func somePrivateFunction() {}
对于函数类型的访问控制
某些函数可能有参数在函数声明中但没有任何返回值。下面的程序声明 a 和 b 作为参数传递给sum()函数。内部函数本身为参数a和b的值是通过调用所述通过调用函数 sum(),其值被打印从而不用返回值。为了使函数的返回类型为私有,声明函数使用 private 修饰整体访问级别。
private func sum(a: Int, b: Int) { let a = a + b let b = a - b println(a, b) } sum(20, 10) sum(40,10) sum(24,6)
当我们使用 playground 运行上面的程序,得到以下结果
(30, 20) (50, 40) (30, 24)
对于枚举类型的访问控制
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") }
当我们使用 playground 运行上面的程序,得到以下结果
Student Marks are: 98,97,95
枚举在Swift语言中将自动接收枚举个体并都具有相同的访问级别。例如,考虑访问固定于三个科目枚举名称,学生的名字和标记被声明为 student 而存在于枚举类中的成员都属于字符串数据类型名称,标记表示为 mark1, mark2 和 mark3 数据类型为整数。要访问无论是学生名称或标记分数。 现在,如果被执行 Switch case 块将打印学生姓名,否则它将打印由学生固定的标记。如果这两个条件都失败默认块将被执行。
子类访问控制
Swift 允许用户子类,可以在当前访问上下文存取的任何类。子类不能比其超类有更高的访问级别。 用户限制一个公共子类写入一个内部超类。
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()
当我们使用 playground 运行上面的程序,得到以下结果
Welcome to Swift Super Class Welcome to Swift Sub Class
常量,变量,属性和下标访问控制
Swift 常量,变量或属性不能被定义比其类型更公开。这是无效一个 public 属性与 private 类型的写法。同样,下标不能超过其索引或返回类型更公开。
当一个常量,变量,属性或下标使用了一个私有类型,则常量,变量,属性或下标,也必须标记为私有:
private var privateInstance = SomePrivateClass()
Getters 和 Setters
getter和setter常量,变量,属性和标自动接收它们属于相同的访问级别的常量,变量,属性或下标。
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
当我们使用 playground 运行上面的程序,得到以下结果
Total Counter is: 100 Newly Added Counter 100 Total Counter is: 800 Newly Added Counter 700
访问控制的初始化和默认初始化器
自定义初始化函数可分配的接入级别小于或等于它们初始化的类型。一个必需的初始化必须具有相同的访问级别,因为它们和类相同。一个初始化的参数的类型不能比初始化自己的访问级别更私密(更高)。
声明每个和初始化每个子类, “required” 关键字需要在init()函数之前定义。
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()
当我们使用 playground 运行上面的程序,得到以下结果
10 30 10
默认初始化具有相同的访问级别,因为它初始化,除非该类型被定义为公共类型。 当默认初始化定义为公共它被认为是内部的。当用户需要一个公共类型在另一个模块中的一个无参数初始化进行初始化,明确提供一个公共的无参数初始化作为类型定义的一部分。
对于协议的访问控制
当我们定义一个新的协议,从现有的协议继承的功能,既有声明相同的访问级别以相互继承属性。Swift 访问控制允许用户定义 “public” 协议,它继承自 “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 print = subClass(no1: 30, no2: 50) println("res is: \(res.no1)") println("res is: \(print.no1)") println("res is: \(print.no2)")
当我们使用 playground 运行上面的程序,得到以下结果
res is: 20 res is: 30 res is: 50
扩展访问控制
当用户使用扩展来添加协议的一致性,Swift 不允许用户为扩展提供一个明确的访问级别修饰符。对于在每个协议的扩展,要求实现的默认访问级别设置自己的协议访问级别。
对于泛型访问控制
泛型允许用户指定最小访问级别来访问类型约束其类型参数。
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()
当我们使用 playground 运行上面的程序,得到以下结果
[Swift] [Swift, Generics] [Swift, Generics, Type Parameters] [Swift, Generics, Type Parameters, Naming Type Parameters]
对于类型别名访问控制
用户可以定义类型别名对待不同的访问控制类型。 相同的访问级别或不同的访问级别可以由用户定义。当类型别名为 “private” 及其相关成员可以声明为 “private,内部 public 类型 ”。当类型别名是公共成员不能是别名为 “internal” 或 “private” 的名称
定义任何类型别名被视为用于不同类型的访问控制的目的。一个类型别名可以具有小于或等于它的一个访问级别别名的类型的访问级别。例如,private类型别名可以别名为 private, internal, 或 public,而 public 类型别名不能别名为 internal 或 private 类型。
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)
当我们使用 playground 运行上面的程序,得到以下结果
[Swift] [Swift, Generics] [Swift, Generics, Where Clause] [Swift, Generics, Where Clause]