Swift - 訪問控制



訪問控制用於限制對程式碼或模組指定部分的訪問。它防止未經授權的訪問並實現封裝。訪問控制機制控制對類、結構體和列舉的方法和屬性的訪問。

協議中的常量、變數和函式受到限制,並允許透過訪問控制以全域性和區域性方式訪問。應用於屬性、型別和函式的訪問控制可以稱為“實體”。

訪問控制模型基於模組和原始檔。模組定義為單個程式碼分發單元,可以使用關鍵字“import”匯入。原始檔定義為模組內的一個單個原始碼檔案,用於訪問多個型別和函式。

Swift 中的訪問級別

Swift 支援以下訪問級別:

訪問級別 定義
開放 (Open) 這是限制最少的訪問級別。它僅適用於類及其成員。它允許在另一個模組中對類和類成員進行子類化或重寫。
公開 (Public) 它允許從同一模組或不同模組內的任何原始檔中訪問實體。
內部 (Internal) 它允許從定義它們的模組內的任何原始檔中使用實體,但不允許在該模組之外使用。
私有 (Private) 它將實體的使用限制在其自己的定義原始檔中。它隱藏特定程式碼功能的實現細節。這是限制最嚴格的訪問級別。
檔案私有 (File-Private) 它也限制實體的使用在其自己的定義原始檔中。當這些細節在整個檔案中使用時,它會隱藏特定程式碼功能的實現細節。

使用訪問級別的規則

以下是開發人員在使用訪問級別時必須瞭解的一些規則:

  • 公開變數不能定義為內部、檔案私有或私有。

  • 函式的訪問級別不能高於其引數和返回型別的訪問級別。

  • 所有實體的預設訪問級別為內部。

  • 單目標應用程式的預設訪問級別為內部。

  • 框架的預設訪問級別為開放或公開。

語法

public class SomePublicClass {}
internal class SomeInternalClass {}
private class SomePrivateClass {}

public var somePublicVariable = 0
internal let someInternalConstant = 0
private func somePrivateFunction() {}

函式型別的訪問控制

某些函式可能在函式內部宣告引數,而沒有任何返回值。以下程式將 a 和 b 宣告為 sum() 函式的引數。在函式本身內部,透過呼叫函式呼叫 sum() 傳遞引數 a 和 b 的值,並列印其值,從而消除返回值。

要將函式的返回型別設為私有,請使用 private 修飾符宣告函式的整體訪問級別。

示例

演示函式型別訪問控制的 Swift 程式。

// Private function
private func sum(a: Int, b: Int) {
   let a = a + b
   let b = a - b
   print(a, b)
}

// Calling the function
sum(a: 20, b: 10)
sum(a: 40, b: 10)
sum(a: 24, b: 6)

輸出

它將產生以下輸出:

30 20
50 40
30 24

列舉型別的訪問控制

Swift 中的列舉會自動為列舉的各個情況接收相同的訪問級別。例如,考慮訪問學生姓名和三門科目考試分數,列舉名稱宣告為 student,列舉類中存在的成員是屬於字串資料型別的名稱,分數表示為 mark1、mark2 和 mark3,資料型別為整數。

訪問他們獲得的學生姓名或分數。現在,switch case 將列印學生的姓名(如果執行該 case 塊),否則將列印學生獲得的分數。

示例

演示列舉型別訪問控制的 Swift 程式。

// Enumeration
public enum Student {
   case Name(String)
   case Mark(Int, Int, Int)
}

var studDetails = Student.Name("Swift")
var studMarks = Student.Mark(98, 97, 95)

switch studDetails {
   case .Name(let studName):
      print("Student name is: \(studName).")
   case .Mark(let Mark1, let Mark2, let Mark3):
      print("Student Marks are: \(Mark1), \(Mark2), \(Mark3).")
}

輸出

它將產生以下輸出:

Student name is: Swift.

子類的訪問控制

Swift 允許使用者對可在當前訪問上下文中訪問的任何類進行子類化。子類的訪問級別不能高於其超類的訪問級別。使用者被限制為不能編寫內部超類的公開子類。

示例

演示子類訪問控制的 Swift 程式。

// Class
public class Cricket {
   internal func display() {
      print("Welcome to Swift Super Class")
   }
}

// Subclass
internal class Tennis: Cricket {
   override internal func display() {
      print("Welcome to Swift Sub Class")
   }
}

let cricketInstance = Cricket()
cricketInstance.display()

let tennisInstance = Tennis()
tennisInstance.display()

輸出

它將產生以下輸出:

Welcome to Swift Super Class
Welcome to Swift Sub Class

常量、變數、屬性和下標的訪問控制

我們可以藉助訪問控制來控制常量、變數、屬性和下標的可見性。當常量、變數、屬性或下標使用私有型別時,則必須將該常量、變數、屬性或下標標記為私有。

我們不能使用私有型別編寫公開屬性。類似地,下標的公開級別不能高於其返回型別。

示例

private var privateInstance = SomePrivateClass()

getter 和 setter 的訪問控制

我們可以獨立設定 getter 和 setter 的訪問控制以控制其可見性。getter 和 setter 的訪問級別由它們所屬的常量、變數、屬性或下標的訪問級別決定。

示例

演示 getter 和 setter 訪問控制的 Swift 程式。

class Samplepgm {
   private var counter: Int = 0{
      willSet(newTotal){
         print("Total Counter is: \(newTotal)")
      }
      didSet{
         if counter > oldValue {
            print("Newly Added Counter \(counter - oldValue)")
         }
      }
   }
}

let NewCounter = Samplepgm()
NewCounter.counter = 100

輸出

它將產生以下輸出:

Total Counter is: 100
Newly Added Counter 100
Total Counter is: 800
Newly Added Counter 700

初始化器和預設初始化器的訪問控制

在 Swift 中,我們可以為初始化器指定訪問控制。對於自定義初始化器,我們可以分配小於或等於它們初始化的型別的訪問級別。必需初始化器的訪問級別必須與其所屬的類相同。

而預設初始化器的訪問級別與其初始化的型別相同,除非該型別定義為公開型別。當預設初始化器定義為公開時,它被認為是內部的。如果我們需要在另一個模組中使用無引數初始化器初始化公開型別,請在型別的定義中顯式提供公開的無引數初始化器。

此外,初始化器的引數不能比初始化器自身的訪問級別更私有。“required”關鍵字需要在 init() 函式之前定義,才能宣告初始化器的每個子類。

示例

演示初始化器訪問控制的 Swift 程式。

class ClassA {
   required init() {
      let a = 10
      print(a)
   }
}
class ClassB: ClassA {
   required init() {
      let b = 30
      print(b)
   }
}
let instanceA = ClassA()
let instanceB = ClassB()

輸出

它將產生以下輸出:

10
30
10

協議的訪問控制

當我們定義一個新協議來繼承現有協議的功能時,兩者都必須宣告相同的訪問級別才能繼承彼此的屬性。Swift 訪問控制不允許使用者定義從“內部”協議繼承的“公開”協議。

示例

演示協議訪問控制的 Swift 程式。

// Public protocol
public protocol tcpprotocol {
   init(no1: Int)
}

// Public class
public class mainClass {
   var no1: Int 
   
   // Initializer 
   init(no1: Int) {
      self.no1 = no1 
   }
}

// Class that uses protocol and class
class subClass: mainClass, tcpprotocol {
   var no2: Int
   init(no1: Int, no2 : Int) {
      self.no2 = no2
      super.init(no1:no1)
   }

   // Requires only one parameter for convenient method
   required override convenience init(no1: Int)  {
      self.init(no1:no1, no2:0)
   }
}

let obj1 = mainClass(no1: 20)
let obj2 = subClass(no1: 30, no2: 50)

print("res is: \(obj1.no1)")
print("res is: \(obj2.no1)")
print("res is: \(obj2.no2)")

輸出

它將產生以下輸出:

res is: 20
res is: 30
res is: 50

泛型的訪問控制

泛型允許使用者指定最小訪問級別以訪問其型別引數上的型別約束。

示例

演示泛型訪問控制的 Swift 程式。

public struct TOS<T> {
   var items = [T]()
    
   mutating func push(item: T) {
      items.append(item)
   }

   mutating func pop() -> T {
      return items.removeLast()
   }
}

var tos = TOS<String>()
tos.push(item: "Swift 4")
print(tos.items)

tos.push(item: "Generics")
print(tos.items)

tos.push(item: "Type Parameters")
print(tos.items)

tos.push(item: "Naming Type Parameters")
print(tos.items)
let deletedTos = tos.pop()

輸出

它將產生以下輸出:

[Swift 4]
[Swift 4, Generics]
[Swift 4, Generics, Type Parameters]
[Swift 4, Generics, Type Parameters, Naming Type Parameters]

類型別名的訪問控制

在 Swift 中,我們可以定義類型別名來處理不同的訪問控制型別。可以定義相同的訪問級別或不同的訪問級別。類型別名的訪問級別可以小於或等於其引用的型別的訪問級別。

當類型別名為“私有”時,其關聯成員可以宣告為“私有、內部或公開型別”。當類型別名為公開時,成員不能別名為“內部”或“私有”名稱。

示例

演示類型別名訪問控制的 Swift 程式。

// Defining a type alias with their access control
public typealias alias1 = Int
internal typealias alias2 = Double

// Class using the type aliases
class AliasClass {
   var publicValue: alias1 = 33
   var internalValue: alias2 = 18.22

   func displayData() {
      print("Public Value: \(publicValue)")
      print("Internal Value: \(internalValue)")
   }
}

// Creating instance of class
let obj = AliasClass()
obj.displayData()

輸出

它將產生以下輸出:

Public Value: 33
Internal Value: 18.22
廣告