聊一下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。