Swift存取控制


要限制對程式碼塊的存取,模組和抽象是通過存取控制完成的。 可以根據存取控制機制的屬性,方法,初始化程式和下標來存取類,結構和列舉。 協定中的常數,變數和函式受到限制,並允許通過存取控制作為全域性和區域性存取。 應用於屬性,型別和功能的存取控制可稱為「實體」。

存取控制模型基於模組和原始檔。

模組被定義為單個程式碼分發單元,使用關鍵字import匯入。原始檔定義為單個原始碼檔案,在模組中用於存取多種型別和功能。

Swift 4語言提供了三種不同的存取級別。 它們是公共,內部和私有存取。

編號 存取級別 定義
1 Public 允許在定義模組的任何原始檔中處理實體,從另一個匯入定義模組的模組的原始檔。
2 Internal 允許實體在定義模組的任何原始檔中使用,但不能在該模組之外的任何原始檔中使用。
3 Private 將實體的使用限制在定義原始檔中。 專用存取可以隱藏特定程式碼功能的實現細節。

語法

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

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

功能型別的存取控制

某些函式可能在函式內宣告了引數而沒有任何返回值。 以下程式將ab宣告為sum()函式的引數。 在函式本身內部,引數ab的值通過呼叫函式sum()來傳遞,並且將它的值列印。 要使函式的返回型別為private,請使用private修飾符宣告函式的整體存取級別。

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

sum(a: 20, b: 10)
sum(a: 40, b: 10)
sum(a: 24, b: 6)

當使用playground執行上述程式時,得到以下結果 -

30 20
50 40
30 24

列舉型別的存取控制

範例程式碼

public enum Student {
   case Name(String)
   case Mark(Int,Int,Int)
}
var studDetails = Student.Name("Swift 4")
var studMarks = Student.Mark(98,97,95)

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

}

當使用playground執行上述程式時,得到以下結果 -

Student Marks are: 98,97,95

對於列舉的個別情況,Swift 4語言中的列舉自動獲得相同的存取級別。 例如,考慮存取三個科目的學生姓名和分數,列舉名稱宣告為Student,列舉類中的Name成員是屬於字串資料型別,分數表示為整數資料型別:mark1mark2mark3。 如果執行switch case塊,則switch case將列印學生姓名,否則將列印學生保護的分數。 如果兩個條件都失敗,則將執行預設塊。

子類的存取控制

Swift 4允許使用者子類化當前存取上下文中存取類。 子類不能具有比超類更高的存取級別。 限制使用者編寫內部超類的公共子類。

public class cricket {
   internal func printIt() {
      print("Welcome to Swift 4 Super Class")
   }
}

internal class tennis: cricket {
   override internal func printIt() {
      print("Welcome to Swift 4 Sub Class")
   }
}

let cricinstance = cricket()
cricinstance.printIt()

let tennisinstance = tennis()
tennisinstance.printIt()

當使用playground執行上述程式時,得到以下結果 -

Welcome to Swift Super Class
Welcome to Swift Sub Class

常數,變數,屬性和下標的存取控制

Swift 4常數,變數或屬性不能定義為公共型別。 使用私有型別編寫公共屬性是無效的。 同樣,下標不能比索引或返回型別更公開。

當常數,變數,屬性或下標使用私有型別時,常數,變數,屬性或下標也必須標記為私有 -

private var privateInstance = SomePrivateClass()

Setter和Getter

常數,變數,屬性和下標的gettersetter自動獲得與它們所屬的常數,變數,屬性或下標相同的存取級別。

範例程式碼

class Samplepgm {
   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
NewCounter.counter = 800

當使用playground執行上述程式時,得到以下結果 -

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

初始化器和預設初始化器的存取控制

自定義初始值設定項分配小於或等於它們初始化型別的存取級別。 必需的初始值設定項必須具有與所屬類相同的存取級別。 初始化程式的引數型別不能比初始化程式自己的存取級別更私有。

要宣告初始化的每個子類需要在init()函式之前使用required關鍵字定義。

class classA {
   required init() {
      let a = 10
      print(a)
   }
}
class classB: classA {
   required init() {
      let b = 30
      print(b)
   }
}
let res = classA()
let print = classB()

當使用playground執行上述程式時,得到以下結果 -

10
30
10

預設初始值設定項具有與初始化型別相同的存取級別,除非該型別被定義為public。 當預設初始化定義為public時,則視為內部。 當使用者需要使用另一個模組中的無引數初始化程式初始化public型別時,請明確提供public無引數初始化程式作為型別定義的一部分。

協定的存取控制

當定義一個新協定來從協定繼承功能時,必須將它們宣告為相同的存取級別以繼承協定的屬性。 Swift 4存取控制將不允許使用者定義繼承自internal協定的public協定。

public protocol tcpprotocol {
   init(no1: Int)
}
public class mainClass {
   var no1: Int      // local storage
   init(no1: Int) {
      self.no1 = no1 // initialization
   }
}
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 res = mainClass(no1: 20)
let print = subClass(no1: 30, no2: 50)

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

當使用playground執行上述程式時,得到以下結果 -

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

擴充套件的存取控制

當使用者使用該擴充套件來新增協定一致性時,Swift 4不允許使用者為擴充套件提供顯式存取級別修飾符。 擴充套件中每個協定要求實現的預設存取級別具有自己的協定存取級別。

泛型的存取控制

泛型允許使用者指定最小存取級別以存取型別引數的型別約束。

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 deletetos = tos.pop()

當使用playground執行上述程式時,得到以下結果 -

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

型別別名的存取控制

使用者可以定義型別別名以處理不同的存取控制型別。 使用者可以定義相同的存取級別或不同的存取級別。 當型別別名為private時,關聯成員可以宣告為:private, internalpublic型別。 當型別別名為public時,成員不能將別名作為internalprivate名稱。

為了存取控制的目的,定義的任何型別別名都視為不同型別。型別別名的存取級別可以小於或等於別名型別的存取級別。 例如,私有型別別名可以為私有,內部或公共型別設定別名,但公共型別別名不能為內部或私有類別設定別名。

public protocol Container {
   associatedtype ItemType
   mutating func append(item: ItemType)
   var count: Int { get }
   subscript(i: Int) -> ItemType { get }
}
struct Stack<T>: Container {
   // original Stack<T> implementation
   var items = [T]()
   mutating func push(item: T) {
      items.append(item)
   }
   mutating func pop() -> T {
      return items.removeLast()
   }

   // conformance to the Container protocol
   mutating func append(item: T) {
      self.push(item: item)
   }
   var count: Int {
      return items.count
   }
   subscript(i: Int) -> T {
      return items[i]
   }
}
func allItemsMatch<
   C1: Container, C2: Container
   where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
   (someContainer: C1, anotherContainer: C2) -> Bool {

   // check that both containers contain the same number of items
   if someContainer.count != anotherContainer.count {
      return false
   }

   // check each pair of items to see if they are equivalent
   for i in 0..<someContainer.count {
      if someContainer[i] != anotherContainer[i] {
         return false
      }
   }
   // all items match, so return true
   return true
}
var tos = Stack<String>()
tos.push(item: "Swift 4")
print(tos.items)

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

tos.push(item: "Where Clause")
print(tos.items)

var eos = ["Swift 4", "Generics", "Where Clause"]
print(eos)

當使用playground執行上述程式時,得到以下結果 -

[Swift 4]
[Swift 4, Generics]
[Swift 4, Generics, Where Clause]
[Swift 4, Generics, Where Clause]

Swift編碼和解碼

Swift 4引入了一個新的Codable協定,它允許在不編寫任何特殊程式碼的情況下序列化和反序列化自定義資料型別 - 而不必擔心丟失值型別。

struct Language: Codable {
   var name: String
   var version: Int
}
let swift = Language(name: "Swift", version: 4)
let java = Language(name: "java", version: 8)
let R = Language(name: "R", version: 3

請注意,Language符合Codable協定。 現在將使用一條簡單的線將其轉換為Json資料表示。

let encoder = JSONEncoder()
if let encoded = try? encoder.encode(java) {
   //Perform some operations on this value.
}

Swift將自動編碼資料型別中的所有值,可以使用解碼器功能解碼資料。

let decoder = JSONDecoder()
if let decoded = try? decoder.decode(Language.self, from: encoded) {
   //Perform some operations on this value.
}

JSONEncoder及其屬性列表對應的PropertyListEncoder都有很多選項可用於自定義它們的工作方式。