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
广告