Swift访问控制

时间:2020-02-23 14:43:59  来源:igfitidea点击:

在本教程中,我们将讨论Swift Access Control。
在掌握它之前,让我们了解一个将在本教程中使用的重要术语:"模块"。

模块只是通过import语句在其他模块中使用的一捆代码。
简单来说,模块只是一个文件夹,您可以其中保存快速文件。

Swift访问控制

访问控制处理您的代码的限制。
通过定义对类,函数,属性,枚举,协议的访问,您可以在XCode项目中的所需位置使用这些内容,并将其隐藏在不需要的地方。

注意:每当我们在本教程中编写实体时,都会引用以下内容:类,函数,属性,枚举,协议。

Swift访问级别

以下是为您提供访问控制的主要级别。
按从最低到最高的顺序排列。

  • open:限制最少。
    可以从当前模块中的任何文件或者其他模块文件中访问实体。

类。
带有open修饰符的类/成员可以在当前模块或者其他模块中的任何位置继承/重写。

  • public:限制较少。
    可以在相同或者不同的模块中访问实体。

具有open修饰符的类/成员不能在当前模块以外的任何其他模块中继承/重写。

  • 内部:默认访问级别。
    如果未指定访问级别,则这是默认访问级别。
    它允许实体在其定义的模块中的任何源文件中使用,但不能在该模块之外使用。
    同样的规则也适用于继承。

  • fileprivate:此访问级别将实体的使用限制为仅当前文件。
    子类化" fileprivate"类将需要您将子类访问级别指定为" fileprivate"或者更严格的级别。

  • private:最严格的限制。
    具有此访问级别的实体只能在随附的范围内访问。
    同样,对该声明的任何扩展都可以访问。

以下流程恰当地显示了每个访问级别。

Swift访问控制示例

类和属性的语法如下所示:

open class AnOpenClass {}
public class APublicClass {}
internal class ExplicitInternalClass {}
fileprivate class AFilePrivateClass {}
private class APrivateClass {}

open func AnOpenFunction() {} 
public var APublicVariable = 0
internal let ExplicitInternalConstant = 0
fileprivate func AFilePrivateFunction() {}
private func APrivateFunction() {}

func ImplicitInternalFunction(){}
class ImplicitInternalClass {}

Swift访问控制–属性

一个Property – var,让我们不能对其分配的类型拥有更多的访问权限。

class A {
  
}
public var a = A() //compiler error.

open class B{
 //Your code
}
public var b = B()

private class C{
  //Your code
}
private var c = C()

"类A"是内部的,因此当" a"是公共的(更多访问权限)时,它将无法编译。
私有类必须定义一个私有属性。

Swift访问控制Getter和Setter方法

属性上的getter和setter将获得与该属性上定义的相同的访问级别。
我们也可以在设置器上设置不同的访问级别。
但是,setter不能具有比该属性更高的访问级别。
一个fileprivate的getter和setter属性:

var length : Double = 5.0
let breadth : Double = 1.1

fileprivate var area : Double {
  
  get{
      return length*breadth
  }
  set(newArea)
  {
      length = newArea/breadth
  }
}

该getter将始终具有与该属性相同的访问级别。
以下是公共获取者和私有获取者。

var length : Double = 5.0
let breadth : Double = 1.1

public private(set) var area : Double {
  
  get{
      return length*breadth
  }
  set(newArea)
  {
      length = newArea/breadth
  }
}

由于设置器比属性及其获取器具有更多的访问权限,因此以下操作将失败

var length : Double = 5.0
let breadth : Double = 1.1

private fileprivate(set) var area : Double { //compiler error
  
  get{
      return length*breadth
  }
  set(newArea)
  {
      length = newArea/breadth
  }
}

Swift访问控制–类

为类定义的访问级别可以应用于也可以不应用于成员和功能。
具有公共访问权限的类意味着,除非另有说明,否则默认情况下其成员将具有内部访问权限。
下图显示了两个类。
一类的私人成员无法在另一类中访问。

子类的访问控制

规则1:子类的访问级别不能高于其父类。

以下示例无法编译。

class A {
 //Internal class
}

public class B : A {
 //public subclass not allowed.
}

规则2:覆盖的方法可以具有比其超类对应方法更高的访问级别。

class A {
 //Internal class
  fileprivate func hey() {
          print("Hey")
  }
  
  internal func hello() {
      print("Hello")
  }
}

fileprivate class B : A {
  override public func hey() {
      print("B")
  }
  override fileprivate func hello() {
      print("B")
  }   
}

规则3:私有功能不能被覆盖。
覆盖的函数不能是私有的。

class A {
 //Internal class
  fileprivate func hey() {
          print("Hey")
  }
  
  internal func hello() {
      print("Hello")
  }
}

fileprivate class B : A {
  override open func hey() {
      print("B")
  }
  override private func hello() { //compiler error.
      print("B")
  }
}

Swift访问控制–元组

Swift元组的访问级别将是存在的元素中限制性最强的元素的级别。

fileprivate class F1{
  
  var str : String
  var number: Int
  init(s: String, n: Int) {
      str = s
      number = n
  }
}
private class F2{
  
  var str : String
  var number: Int
  init(s: String, n: Int) {
      str = s
      number = n
  }
}
class G{
  //compiler error below.
  var tuple : (F1,F2) =  (F1(s: "Anupam",n: 101), F2(s: "theitroad.local",n: 102))
}

在上面的代码中,必须将元组的访问级别设置为私有,这两个级别的限制更大。

private var tuple : (F1,F2) =  (F1(s: "Anupam",n: 101), F2(s: "theitroad.local",n: 102))

具有功能类型的Swift访问控制

快速的函数(如元组)具有的访问级别等于参数和返回类型中最严格的级别。
但是,您也必须明确指定功能的访问级别。
如果指定的访问级别与计算出的访问级别不匹配,则会引发编译器错误。
以下代码看起来不错,但无法编译:

fileprivate class F1{
  
  var str : String
  var number: Int
  init(s: String, n: Int) {
      str = s
      number = n
  }
}
class G{
  func hey(s: String,y: Int) -> F1 //compiler error.
  {
      print("\(s) and \(y)")
      return F1(s: s, n: y)
  }
}

" hey()"的返回类型是" F1",它是一个文件私有类。
因此,您必须使函数fileprivate。

具有初始化函数的Swift Access Control

Swift初始化程序必须具有与其定义的参数相同或者更低的访问级别。
以下代码在类G中定义了一个初始化器,由于其具有更高的访问级别,该初始化器将失败。

fileprivate class F1{
  
  var str : String
  var number: Int
  init(s: String, n: Int) {
      str = s
      number = n
  }
}
private class F2{
  
  var str : String
  var number: Int
  init(s: String, n: Int) {
      str = s
      number = n
  }
}
class G{
  private var tuple : (F1,F2)
  init(f1: F1, f2: F2) { //compiler error.
      tuple = (F1(s: "Anupam",n: 101), F2(s: "theitroad.local",n: 102))
  }
}

我们可以将上面的初始化程序设置为fileprivate或者private

所需的初始化程序遵循与初始化程序相同的访问规则,并遵循以下规则:访问级别应与封闭类的访问级别相同。

因此,仅将fileprivate级别保持在所需的init上将产生以下错误。

因此,或者将参数设为类的相同类型,或者反之亦然。
其中我们将稍后做,并将类设为fileprivate
继续我们先前的代码,使用必需的init将使class G看起来像这样:

fileprivate class G{
  private var tuple : (F1,F2)
  required fileprivate init(f1: F1, f2: F2) {
      tuple = (F1(s: "Anupam",n: 101), F2(s: "theitroad.local",n: 102))
  }
}

结构类型的默认成员级初始化程序

对于结构初始化程序,我们必须根据成员将初始化程序设置为以下级别

  • 如果任何初始化者成员是"私有"或者"文件私有",则初始化应为"文件私有"。

  • 否则,默认情况下,init是内部的。

继续前面的" fileprivate" F1和" private" F2类代码,以下代码段适用于该结构的默认初始化程序。

struct StructureExample {
private var tuple : (F1,F2)

  fileprivate init(f1: F1, f2: F2) {
      tuple = (F1(s: "Anupam",n: 101), F2(s: "theitroad.local",n: 102))
  }
}

总结:元组必须设置为低于或者等于其元素级别的访问级别

快速访问控制示例–协议

在定义该协议时必须设置协议访问级别。
协议功能/要求必须定义相同的访问级别。
就像子类化一样,如果一个协议继承自另一个协议,则它不能具有比继承的协议更高的访问级别。

private protocol ProtocolA{
  //Your code
}

private protocol ProtocolB : ProtocolA{
  //Your code
}

您不能将ProtocolB设置为更高的级别,例如fileprivate

协议一致性

  • 类可以符合访问级别较低的协议。

  • 如果一个类是公共的并且协议是"私有的",那么类型一致性是"私有的"。

  • 总是考虑的较低者。

  • 如果协议方法是在类/结构/枚举中实现的,则必须将它们设置为等于协议访问级别或者更高的访问级别。

快速访问控制–枚举

枚举的访问级别将应用于所有情况

private enum Color{
  case red
  case blue
}

红色和蓝色具有相同的访问类型"专用"

原始值的访问级别应大于或者等于枚举访问级别。

快速访问控制–扩展

在扩展中添加的任何类型成员必须具有与在要扩展的原始类型中声明的类型成员相同的默认访问级别。
要将访问级别更改为与该类不同的访问级别,您只需要在扩展程序上添加访问修饰符,它也将更改扩展程序成员的默认访问权限级别,除非您明确设置成员级别。

您不能声明具有public或者internal或者open扩展名的private/fileprivate类

private class H{
  private var hello = "Hi"
}
//compiler error below
public extension H{
  var newHello:String  {return "Yeah"}
}

我们可以从扩展名中的类/结构访问私有成员。
我们可以从另一扩展名访问私人成员。

快速访问控制–泛型和类型别名

  • 通用类型或者通用功能的访问级别是通用类型或者功能本身及其任何成员/返回类型的访问级别的最小值。

  • 类型别名的访问级别可以小于或者等于其别名的访问级别。

这与子类化相同。
类型别名不能使用比其类型更高的访问级别。