Swift和C++,Java一样,也有访问控制的概念。通过访问权限的控制,我们可以对外隐藏内部的代码细节,防止修改。
Swift的访问控制是基于模块(modules)和源文件(source file)
Swift的模块概念是这样的:
1、一个App bundle,或者一个framework都可以看成一个独立的module。 你可以使用import来引入别的module到你的module中来。
当你将你的代码打包成一个framework,这个framework就是一个module。里面的所有的东西都是属于这个framework,无论你将这个framework引入到别的framework或app中。
2、一个源文件里面虽然可以定义多个类,但是建议一般一个源文件建立一个类。
Swift的访问权限有三个:
1、public 这个权限允许同一个module内部的所有源代码访问,同时允许其他引入了该module的module使用。总的来说就是全开放
2、internal 这个权限允许同一个module内部的所有源代码访问,不允许其他module使用。
3、private 这个权限仅允许同一个source file的代码访问。
Swift的默认访问权限是internal。
public是最高访问权限,而private是最低访问权限。
Swift的权限编程原则:
一、高权限的东西不能包含在低权限的东西里面。
举例:
1、说就是一个public的类型不能定义在一个声明为internal的类型里面。
2、方法的权限不能高于参数和范围值的权限。否则会导致这个方法没法使用。
二、单一app中
一般就用默认的internal就行了。如果你想对其他源文件隐藏,可以使用private。
三、framework中
对于要提供给外边使用的属性,方法。必须使用public权限。其他的可以默认使用internal。如果相对framework里面的其他源文件隐藏,可以使用private。
四、单元测试中
单元测试和我们编写的代码属于不同的module,所以测试模块一般只能访问到public的东西。但是在引入要测试的模块的时候可以加上@testable,这样测试模块就可以访问了。然后要允许被测试的单元可以测试。
示例:
public class SomePublicClass {}
internal class SomeInternalClass {}
private class SomePrivateClass {}
public var somePublicVariable = 0
internal let someInternalConstant = 0
private func somePrivateFunction() {}
给类型定义访问权限的时候,会影响到类型里面的成员(属性,方法,下标,构造器)。
1、将一个类型定义为private后,它里面的成员都是private的。
2、将一个类型定义为public或internal后,它里面的成员还是internal的。如果要某个成员变为public,必须在该成员里面加上public。
Tuple
Tuple的访问权限由tuple成员里面访问权限最小那个决定。
方法
方法的访问权限由方法的参数和返回值中最小权限的那个决定。当方法的权限是private的时候,方法的前面要加上private关键字。
枚举类
枚举类型的成员变量的访问权限决定于枚举类型。例如你定义了一个public的枚举类型,那么它里面的case成员都是public的,不允许单独给每个case成员定义访问权限。
case成员的raw vlaue的值的权限必须大于等于枚举类的访问权限。
内部类
定义在private类型里面的内部类是private权限;定义在public或internal类型里面的内部类默认是internal类型。如果想要定义在public类型里面的内部类变为public的话,需要自己显式给内部类加上public。
子类
子类不能比父类具有更高的访问权限。但是可以重写父类当前能访问到的父类成员,而且可以重写成更高权限的成员。
public class A {
private func someMethod() {}
}
internal class B: A {
override internal func someMethod() {
super.someMethod()
}
}
这里再补充一点,如果父类是public类的,继承之后不加权限修饰符的话,那么这个子类是internal的
属性,常量,变量和下标的访问权限不能超过它所属的类型的权限。
getter和setter方法
这两个方法的访问权限默认和属性的是一样的。但是可以修改setter的权限,可以将setter的权限修改得比属性的权限低,但是不能比属性的权限高。
public class Animal {
public internal(set) var age: Int = 0
}
构造器
构造器的权限不能大于它所属类型的权限。除了标志有require的构造器之外,这种构造器的权限必须和它所属的类的权限相同。
构造器参数的权限不能低于构造器。
默认构造器
默认构造器的默认权限和类型权限一样。但是如果类型是public,那么默认构造器还是internal的,想要public的无参构造器必须自己实现。
对于结构体的memberwise构造器,想要public的,也要自己实现。
协议
协议的需求的权限和协议权限是一样的,协议是public的,那么需求也是public的。
继承的协议的权限最多只能有父类的权限。例如:不能继承一个internal的协议为一个public协议。
协议的一致性
类型可以实现比自己访问权限低的协议。比如,可以定义一个public的类,它可以实现一个internal的类,并且只能在定义了该协议的模块中使用。
实现了协议的类访问权限是它本身和采用协议中的最低访问权限。也就是说如果一个类是public的级别,实现的是internal的协议,那么采用这个协议之后,该类的访问权限也是internal的。
如果你采用了协议,那么实现协议方法之后,该方法的访问权限遵循协议的访问级别。例如:一个public的类,采用了internal的协议之后,那么该类的实现协议的方法至少也是internal的。
扩展
扩展的默认访问权限由所扩展类型的访问权限决定。
如果你扩展了一个public的类型,那么扩展的成员的默认访问权限就是internal。如果扩展一个private类型,那么扩展的默认访问权限就是private。
当然可以自己给扩展自定义访问权限。但是权限不能超过所扩展的类型。另外可以自己给扩展成员再自定义权限。
如果你是用扩展来实现协议,那么这个扩展不允许自定义权限,它的权限由协议的权限决定。
泛型
泛型分为泛型类型和泛型方法
泛型类型的权限是 泛型类型和泛型参数 之间最小的那个权限。
泛型方法的权限是 泛型方法和泛型参数 之间最小的那个权限。
类型别名
每个类型别名都可以看做是对类型的访问权限的定义。
但是类型别名的权限必须小于或等于要别名的类型。比如一个private的类型别名可以为private,public,internal的类型进行别名;但是一个public的类型别名不能为internal和private的类型进行别名。