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() {}
    
  • 函数类型的访问控制

    某些函数可能在函数内部声明了参数,而没有任何返回值。以下程序将 a 和 b 声明为 sum() 函数的参数。在函数本身内部,参数 a 和 b 的值通过调用函数调用 sum() 传递,并打印其值,从而消除返回值。要将函数的返回类型设为私有,请使用 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 语言中的枚举对于枚举的个别情况自动获得相同的访问级别。例如,考虑访问学生姓名和三个科目中保护的标记,枚举名称声明为学生,枚举类中的成员是属于字符串数据类型的名称,标记表示为数据类型为整数的 mark1、mark2 和 mark3。访问学生姓名或他们得分的分数。现在,如果执行该 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()
    
  • getter和setter

    常量、变量、属性和下标的 getter 和 setter 自动获得与其所属的常量、变量、属性或下标相同的访问级别。
    
    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
    
  • 初始化器和默认初始化器的访问控制

    可以为自定义初始化程序分配一个小于或等于它们初始化的类型的访问级别。必需的初始化程序必须与它所属的类具有相同的访问级别。初始化器的参数类型不能比初始化器自己的访问级别更私密。
    要声明 initialize 'required' 关键字的每个子类,需要在 init() 函数之前定义。
    
    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。当默认初始化定义为公共时,它被认为是内部的。当用户需要使用另一个模块中的无参数初始化程序初始化公共类型时,请明确提供公共无参数初始化程序作为类型定义的一部分。
  • 协议的访问控制

    当我们定义一个新协议来继承现有协议的功能时,两者都必须声明为相同的访问级别以继承彼此的属性。Swift 4 访问控制不允许用户定义继承自“内部”协议的“公共”协议。
    
    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]
    
  • Mooases 类型的访问控制

    用户可以定义类型别名来处理不同的访问控制类型。用户可以定义相同的访问级别或不同的访问级别。当类型别名为“private”时,其关联成员可以声明为“private, internal of public type”。当类型别名为 public 时,成员不能将别名作为“Internal”或“Private”名称
    出于访问控制的目的,您定义的任何类型别名都被视为不同的类型。类型别名的访问级别可以小于或等于它别名的类型的访问级别。例如,私有类型别名可以为私有、内部或公共类型取别名,但公共类型别名不能为内部或私有类型取别名。
    
    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
    
    请注意,语言符合 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 都有很多选项来自定义它们的工作方式。