訪問(wèn)控制(Access Control)
- 在訪問(wèn)權(quán)限控制中Swift提供五個(gè)不同級(jí)別(以下是從高到低依次排列),實(shí)體被訪問(wèn)級(jí)別修飾的內(nèi)容:
- open(級(jí)別最高):允許在定義實(shí)體的模塊、其他模塊中訪問(wèn),允許其他模塊進(jìn)行繼承、重寫(xiě)(open只能用在類(lèi)、類(lèi)成員上)。
- public:允許在定義實(shí)體的模塊、其他模塊中訪問(wèn),不允許其他模塊進(jìn)行繼承、重寫(xiě)。
- internal:只允許在定義實(shí)體的模塊中訪問(wèn),不允許其他模塊中訪問(wèn)。
- fileprivate:只允許在定義實(shí)體的源文件中訪問(wèn)
- private:只允許在定義實(shí)體的封閉聲明中訪問(wèn)
- 絕大部分實(shí)體默認(rèn)都是 internal 級(jí)別
-
訪問(wèn)級(jí)別的使用準(zhǔn)則
- 變量/常量類(lèi)型 >= 變量/常量
- 參數(shù)類(lèi)型、返回值類(lèi)型 >= 函數(shù)
- 父類(lèi) >= 子類(lèi)
- 父協(xié)議 >= 子協(xié)議
- 原類(lèi)型 >= typealias
- 原始值類(lèi)型、關(guān)聯(lián)值類(lèi)型 >= 枚舉類(lèi)型
- 定義類(lèi)型A時(shí)用到的其他類(lèi)型 >= 類(lèi)型A
元組類(lèi)型訪問(wèn)級(jí)別
- 元組類(lèi)型訪問(wèn)級(jí)別,是所有成員類(lèi)型最低的那個(gè)
internal struct Dog {}
fileprivate class Person {}
- Person類(lèi)訪問(wèn)級(jí)別大于等于data1變量級(jí)別
fileprivate var data1: (Dog, Person)
- Person修飾的級(jí)別大于data2變量(private)
private var data2: (Dog, Person)
范型類(lèi)型訪問(wèn)級(jí)別
- 范型類(lèi)型的訪問(wèn)級(jí)別是「類(lèi)型的訪問(wèn)級(jí)別」以及「所有范型類(lèi)型參數(shù)的訪問(wèn)級(jí)別」中最低的那個(gè)
internal class Car {}
fileprivate class Dog {}
public class Person<T1, T2> {}
//Person<Car, Dog>()的訪問(wèn)級(jí)別是fileprivate
fileprivate var p = Person<Car, Dog>()
成員、嵌套類(lèi)型
- 類(lèi)型的訪問(wèn)級(jí)別會(huì)影響成員(屬性、方法、初始化器、下標(biāo))、嵌套類(lèi)型的默認(rèn)訪問(wèn)級(jí)別
- 一般情況下,類(lèi)型為 private 或 filePrivate,那么成員/嵌套類(lèi)型默認(rèn)也是 private 或 filePrivate
- 一般情況下,類(lèi)型為 internal 或 public,那么成員/嵌套類(lèi)型默認(rèn)是 internal
public class PublicClass {
public var p1 = 0 // public
var p2 = 0 // internal
fileprivate func fn1() {} //fileprivate
private func fn2() {}
}
class InternalClass {
var p = 0 // internal
fileprivate func fn1() {}
private func fn2() {}
}
fileprivate class FilePrivatelClass {
func fn1() {}
private func fn2() {}
}
private class PrivatelClass {
func fn1() {} // private
}
- 示例1:子類(lèi)權(quán)限小于父類(lèi)權(quán)限
private class Person {}
fileprivate class Student: Personal {}
編譯器報(bào)錯(cuò):Cannot find type 'Personal' in scope
- 示例2:在全局作用域下定義的private等價(jià)于fileprivate
private struct Dog {
var age: Int = 0
func run() {}
}
fileprivate struct Person {
var dog: Dog = Dog()
mutating func walj() {
dog.run()
dog.age = 18
}
}
- Dog成員訪問(wèn)級(jí)別最低,在外部無(wú)法使用,引起編譯器報(bào)錯(cuò):
private struct Dog {
private var age: Int = 0
private func run() {}
}
fileprivate struct Person {
var dog: Dog = Dog()
mutating func walj() {
dog.run()
dog.age = 18
}
}
- 編譯器報(bào)錯(cuò):'run' is inaccessible due to 'private' protection level
- 編譯器報(bào)錯(cuò):'age' is inaccessible due to 'private' protection level
成員的重寫(xiě)
- 字類(lèi)重寫(xiě)成員的訪問(wèn)級(jí)別必須 ≥ 字類(lèi)的訪問(wèn)級(jí)別,或者 ≥ 父類(lèi)被重寫(xiě)成員的訪問(wèn)級(jí)別
- 父類(lèi)的成員不能被成員作用域外定義的子類(lèi)重寫(xiě)。
Getter Setter
- getter、setter默認(rèn)自動(dòng)接受它們所屬環(huán)境的訪問(wèn)級(jí)別
- 可以給setter單獨(dú)設(shè)置一個(gè)比getter更低的訪問(wèn)級(jí)別,用以限制寫(xiě)的權(quán)限。
class Personal {
//private(set)只讀,不能寫(xiě)入
private(set) var age = 0
//只讀的計(jì)算屬性
fileprivate(set) public var weight: Int {
set { }
get { 10 }
}
//只讀的下標(biāo)
internal(set) public subscript(index: Int) -> Int {
set { }
get { 10 }
}
}
如果嘗試賦值編譯器報(bào)錯(cuò):
Cannot assign to property: 'age' setter is inaccessible
- fileprivate(set)
//是全局變量,當(dāng)前文件都可以訪問(wèn),但不能改變它。
fileprivate(set) public var number = 10
初始化器
1.如果一個(gè)
public類(lèi)想在另一個(gè)模塊調(diào)用編譯器生成的默認(rèn)無(wú)參初始化器,必須顯示提供public的無(wú)參初始化器2.因?yàn)?
public類(lèi)的默認(rèn)初始化器是internal級(jí)別3.
required初始化器必須跟它所屬類(lèi)擁有相同的訪問(wèn)級(jí)別
- 4.如果結(jié)構(gòu)體有
private、fileprivate的存儲(chǔ)實(shí)例屬性,那么它的成員初始化器也是private、fileprivate
struct MyPoint {
private var x = 0
var y = 0
}
//var p = MyPoint(x: 10, y: 20) //成員初始化器
var p2 = MyPoint()
- 默認(rèn)是 internal
枚舉
- 不能給
enum的每個(gè)case單獨(dú)設(shè)置訪問(wèn)級(jí)別 - 每個(gè)
case自動(dòng)接受enum的訪問(wèn)級(jí)別 -
public enum { }定義的case也是public
public enum Season {
case spring
case summer
case aotumn
case winter
}
給case修飾權(quán)限報(bào)錯(cuò):'private' modifier cannot be applied to this declaration
協(xié)議
- 協(xié)議中定義的要求自動(dòng)接受協(xié)議的訪問(wèn)級(jí)別,不能單獨(dú)設(shè)置訪問(wèn)級(jí)別
- public協(xié)議定義的要求也是public
- 協(xié)議實(shí)現(xiàn)的訪問(wèn)級(jí)別必須 >= 類(lèi)型的訪問(wèn)級(jí)別,或者 >= 協(xié)議的訪問(wèn)級(jí)別
public protocol Runnable {
func run()
}
public class Person : Runnable {
public func run() { }
}
擴(kuò)展
- 如果有顯式設(shè)置擴(kuò)展的訪問(wèn)級(jí)別,擴(kuò)展添加的成員自動(dòng)接收擴(kuò)展的訪問(wèn)級(jí)別
- 如果沒(méi)有顯式設(shè)置擴(kuò)展的訪問(wèn)級(jí)別,擴(kuò)展添加的成員的默認(rèn)訪問(wèn)級(jí)別,跟寫(xiě)在類(lèi)型中定義的成員一樣。
class Person {
func run() {}
}
extension Person { }
class Person { }
private extension Person {
func run() {}
}
- 可以單獨(dú)給擴(kuò)展添加的成員設(shè)置訪問(wèn)級(jí)別
extension Person {
private func run() {}
}
- 不能給用于遵守協(xié)議的擴(kuò)展顯式設(shè)置擴(kuò)展的訪問(wèn)級(jí)別
fileprivate extension Person: Equatable {
func test(){}
}
編譯報(bào)錯(cuò):'fileprivate' modifier cannot be used with extensions that declare protocol conformances
在同一文件中的擴(kuò)展,可以寫(xiě)成類(lèi)似多個(gè)部分的類(lèi)型聲明
在原本的聲明中聲明一個(gè)私有成員,可以在同一文件的擴(kuò)展中訪問(wèn)它
在擴(kuò)展中聲明一個(gè)私有成員,可以在同一文件中的其他擴(kuò)展中、原本聲明中訪問(wèn)它
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() }
}