在访问权限控制中,swift
中提供了5
个不同的访问级别(以下是从高到低排列,实体指被访问级别修饰的内容)
-
open
:允许在定义实体的模块、其他模块中访问,允许其他模块进行继承、重写(open
只能用在类、类成员上)-
Person
类可以在整个项目任何类中使用 -
Person
类可以在其他模块(动态库等)使用,比如一些第三方的库中定义的类
-
open class Person { }
public
:允许在定义实体的模块、其他模块中访问,不允许其他模块进行继承、重写
public class Person { }
internal
:只允许在定义实体的模块中访问,不允许在其他模块中访问
internal class Person { }
-
fileprivate
:只允许在定义实体的源文件中访问
假如Person
类定义在Test.swift
文件中,那么Person
只能在Test.swift
文件中被操作
fileprivate class Person { }
-
private
:只允许在定义实体的封闭声明中访问
Person
类中的属性age
只能在Person
类中使用,外部无法调用
fileprivate class Person {
private var age: Int = 0
}
访问级别的使用准则
一个实体不可以被更低访问级别的实体定义,比如
- 变量\常量类型
>=
变量\常量
fileprivate class Person { }
internal var person: Person // Variable cannot be declared internal because its type uses a fileprivate type
- 参数类型、返回值类型
>=
函数 - 父类
>=
子类 - 父协议
>=
子协议 - 原类型
>=
typealias
class Person { }
public typealias MyPerson = Person // Type alias cannot be declared public because its underlying type uses an internal type
- 原始值类型、关联值类型
>=
枚举类型
fileprivate typealias MyInt = Int
fileprivate typealias MyString = String
public enum Score {
case point(MyInt) // Enum case in a public enum uses a fileprivate type
case grade(MyString) // Enum case in a public enum uses a fileprivate type
}
- 定义类型
A
时用到的其他类型>=
类型A
元组类型
元组类型的访问级别是所有成员类型最低的那个
internal struct Dog {}
fileprivate class Person {}
//(Dog, Person)的访问级别是fileprivate
fileprivate var data1: (Dog, Person)
private var data2: (Dog, Person)
泛型类型
泛型类型的访问级别是类型的访问级别
以及所有泛型类型参数的访问级别
中最低的那个
internal class Car {}
fileprivate class Dog {}
public class Person<T1, T2> {}
//Person<Car, Dog>()的访问级别是fileprivate
fileprivate var p = Person<Car, Dog>()
成员、嵌套类型
类型的访问级别会影响成员(属性、方法、初始化器、下标)、嵌套类型的默认访问级别
- 一般情况下,类型为
private
或fileprivate
,那么成员\嵌套类型默认也是private
或fileprivate
fileprivate class Person {
var age = 0 //默认fileprivate
func fun() { } //默认fileprivate
enum Season { case spring, summer } //默认fileprivate
}
- 一般情况下,类型为
internal
或public
,那么成员\嵌套类型默认也是internal
getter、setter
-
getter
、setter
默认自动接收它们所属环境的访问级别 - 可以给
setter
单独设置一个比getter
更低的访问级别,用以限制写的权限
fileprivate(set) public var num = 10
class Person {
private(set) var age = 0
fileprivate(set) public var weight: Int {
set {}
get { 10 }
}
internal(set) public subscript(index: Int) -> Int {
set {}
get { index }
}
}
var p = Person()
p.age = 10 // Cannot assign to property: 'age' setter is inaccessible
print(p.age) // 可以访问
初始化器
- 如果一个
public
类想在另一个模块调用编译生成的默认无参数初始化器,必须显示的提供public
的无参初始化器,因为public
类的默认初始化器是internal
级别 -
required
初始化器>=
它的默认访问级别 - 如果结构体有
private
、filtprivate
的储存实例属性,那么它的成员初始化器也是private
、filtprivate
枚举类型的case
不能给enum
的每个case
单独设置访问级别
enum Season {
internal case spring // 'internal' modifier cannot be applied to this declaration
case summer
}
协议
协议中定义的要求自动接收协议的访问级别,不能单独设置访问级别
public
协议定义的要求也是public
protocol Runnable {
private func run() // 'private' modifier cannot be used in protocols
}
扩展
- 如果有显示设置扩展的访问级别,扩展添加的成员自动接收扩展的访问级别
class Person { }
fileprivate extension Person {
func run() { } // 默认 fileprivate
}
- 如果没有显示设置扩展的访问级别,扩展添加的成员的默认访问级别,跟直接在类型中定义的成员一样
class Person { }
extension Person {
func run() { } // 默认跟在Person里面基本一样
}
- 可以单独给扩展添加的成员设置访问级别
class Person { }
extension Person {
private func run() { }
}
- 不能给用于遵守协议的扩展显示设置扩展的访问级别
protocol Runnable { }
class Person { }
//'fileprivate' modifier cannot be used with extensions that declare protocol conformances
fileprivate extension Person: Runnable {
func run() { }
}
- 在同一个文件中扩展,可以写成类似多个部分的类型声明
- 在原本的声明中声明一个私有成员,可以在同一个文件的扩展中访问它
- 在扩展中声明一个私有成员,可以在同一个文件的其他扩展中、原本声明中范文它
public class Person {
private func run0() {}
private func eat0() {
run1()
}
}
extension Person {
private func run1() {}
private func eat1() {
run0()
}
}
extension Person {
private func eat2() {
run1()
}
}
网友评论