聊一下Swift的访问权限

语言: CN / TW / HK

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动

1.访问级别

1.1.open

open的权限无疑是最大的,可以在允许的实体模块,其它模块中访问,并且允许其它模块进行继承和重写。

举个例子:TargetA中有classA,权限是open,TargetB中的classB即可以继承classA,classA的方法,成员变量等也可以被访问。

1.2.public

public和open是差不多的,也是允许在实体模块,其它模块中访问,有一点区别的是,并不允许其它模块进行继承和重写。

举个例子:TargetA中有classA,方法是testA,权限是public,TargetB中有classB,那么在classB中testB方法,就可以初始化var a = classA(),并且调用a.testA()。

1.3.internal

internal只允许在定义的实体模块进行访问,不允许在其它模块中访问。这个也是很多实体默认的权限。

1.4.fileprivate

fileprivate翻译过来就是文件私隐,它只允许在定义的文件中访问。

举个例子:在一个Target中,有classA和classB两个类分别在两个文件,classA当前权限是fileprivate,那么classB是不能访问classA的。如果classA和classB是在同一个文件下,就可以访问。

1.5.private

private只允许在当前定义实体中访问。

举个例子:classA和classB都在同一个文件,classA的权限是private,那classB原理上是不能访问classA的。要访问的话,需要一些情况。这个后面会说到。

2.访问级别的使用准则

一个实体不可以被更低的访问级别的实体定义。

2.1.变量类型的访问级别 >= 变量的访问级别

举个例子:定义一个类 fileprivate class ClassA{},如果定义为internal var classA: ClassA就会报错,权限ClassA的实体类型需要大于变量classA。

2.2.参数类型,返回值类型 >= 函数

举个例子:func testA(_ num: Int) -> Double {},函数的访问级别默认是internal, 参数的num是public,返回值Double也是public。

2.3.父类 >= 子类

相当于说我能访问子类,那么父类也应该要可以访问才对。举个例子:class SupClassA {},子类class ClassA:SupClassA {},父类的默认权限是internal,那么子类就不能为public和open。

3.成员嵌套类型

3.1.类型为private,fileprivate

当类型为private,fileprivate,那么成员的默认类型也是private或fileprivate

举个例子:flieprivate class ClassA { var a = 0 , var b = 0},a和b默认都是fileprivate。

fileprivate class ClassA {
    var a = 0
    private var b = 0
}

3.2.类型为internal,public

当类型为internal,public,成员的默认类型为internal

public class ClassA {
   internal var a = 0
}

4.getter, setter权限

对于读写方面,很多时候我们希望别人读我们的值,而不允许修改我们的值,我们可以这么定义如下:

class ClassA {
   private(set) var age: Int = 0
}

5.测试

5.1.例子1

private class Person {}

fileprivate class Student: Person {}

这个例子能不能编译通过???

在这里就可以看出来,能不能通过是看作用域了。

截图1Person的作用域是classA, 所以Student不能继承父类Person。

截图2Person2的作用域是当前文件,Student2的作用域也是当前文件,所以可以继承。

5.2.例子2

private class ClassA {
    var age: Int = 0
    func testA() {}
}
fileprivate class ClassB {
    var classA = ClassA()

    func testB() {
        classA.age = 2
        classA.testA()
    }
}

看代码,这个和上面的例子1也是一样的,都可以编译通过,那这时候如果我们对ClassA的age和testA定义为private,这时候还可以访问吗???

直接看结果。

why,为什么呢,按之前我们成员嵌套类型中的说法是,classA是private,子类默认就是private,这时候我们写出来为什么就报错了呢???

换一个说法,在ClassB中,能够定义classA,也可以说明在全局中,ClassA也是相当于fileprivate,里面的age和testA也是fileprivate,如果换成private,就相当于作用域在classA中了,所以就会报错。

这时候我们就可以得出一个结论:直接在全局作用域下定义的private等价于fileprivate。