27.访问控制

2021-07-29  本文已影响0人  LucXion

可以明确地给单个类型(类、结构体、枚举)设置访问级别,也可以给这些类型的属性、方法、构造器、下标等设置访问级别。协议也可以被限定在一定访问级别的范围内使用,包括协议里的全局常量、变量和函数。

模块指的是独立的代码单元,框架或应用程序会作为一个独立的模块来构建和发布。在 Swift 中,一个模块可以使用 import 关键字导入另外一个模块。

源文件 就是 Swift 模块中的源代码文件(实际上,源文件属于一个应用程序或框架)。尽管我们一般会将不同的类型分别定义在不同的源文件中,但是同一个源文件也可以包含多个类型、函数等的定义。

访问级别:open、public、internal、fileprivate、private

设置访问级别的基本原则:

  1. 实体不能定义在访问级别更低的实体中,比如public属性不能定义在访问级别是internal的类型内

  2. 函数的访问级别不能高于返回值类型、参数类型的访问级别,导致函数在各个地方可以调用,但参数和返回值不行

单元测试target的访问级别

当你的应用程序包含单元测试 target 时,为了测试,测试模块需要访问应用程序模块中的代码。默认情况下只有 openpublic 级别的实体才可以被其他模块访问。然而,如果在导入应用程序模块的语句前使用 @testable 特性,然后在允许测试的编译设置(Build Options -> Enable Testability)下编译这个应用程序模块,单元测试目标就可以访问应用程序模块中所有内部级别的实体。

自定义类型访问级别对类型成员的影响

  1. 一个 public 类型的所有成员的访问级别默认为 internal 级别,而不是 public 级别。如果你想将某个成员指定为 public 级别,那么你必须显式指定。这样做的好处是,在你定义公共接口的时候,可以明确地选择哪些接口是需要公开的,哪些是内部使用的,避免不小心将内部使用的接口公开。

  2. 如果你将类型指定为 private 或者 fileprivate 级别,那么该类型的所有成员的默认访问级别也会变成 private或者 fileprivate 级别

元组类型

元组不同于类、结构体、枚举、函数那样有单独的定义。元组的访问级别将由元组中访问级别最严格的类型来决定。例如,如果你构建了一个包含两种不同类型的元组,其中一个类型为 internal,另一个类型为 private,那么这个元组的访问级别为 private

函数类型

// 此处定义一个错误的全局的函数定义
func someFunction() -> (SomeInternalClass, SomePrivateClass) {
  // 返回值为元组类型,包含的访问权限分别是 ,internal、private,这种情况需要明确函数的访问权限,否则报错
}

// 正确写法,函数访问权限不高于返回值类型、参数类型权限
private func someFunction() -> (SomeInternalClass, SomePrivateClass) {}

枚举类型

枚举成员的访问级别和该枚举类型相同,你不能为枚举成员单独指定不同的访问级别。

嵌套类型

与自定义类型与自定义类型成员间的访问关系相同

子类

public class A {
    fileprivate func someMethod() {}
}
internal class B: A {
  // 通过重写,可以将父类中低访问权限的方法改为更高的权限,但要符合2大原则
    override internal func someMethod() {}
}

public class A {
    fileprivate func someMethod() {}
}
internal class B: A {
    override internal func someMethod() {
        super.someMethod() // 必须与A在同一个源文件内
    }
}

Getter 和 Setter

常量、变量、属性、下标的 GettersSetters 的访问级别和它们所属类型的访问级别相同。

struct TrackedString {
  //  fileprivate(set),private(set) 和 internal(set)
  // 这意味着 numberOfEdits 属性只能在结构体的定义中进行赋值。numberOfEdits 属性的 Getter 依然是默认的访问级别 internal,但是 Setter 的访问级别是 private,这表示该属性只能在内部修改,而在结构体的外部则表现为一个只读属性。
  // 你不能对其进行赋值。这一限制保护了该记录功能的实现细节,同时还提供了方便的访问方式。
    private(set) var numberOfEdits = 0
    var value: String = "" {
        didSet {
            numberOfEdits += 1
        }
    }
}


public struct TrackedString {
  // 这里将 numberOfEdits 属性的 Getter 的访问级别设置为 public,而 Setter 的访问级别设置为 private
    public private(set) var numberOfEdits = 0
    public var value: String = "" {
        didSet {
            numberOfEdits += 1
        }
    }
    public init() {}
}

构造器

自定义构造器的访问级别可以低于或等于其所属类型的访问级别。唯一的例外是 必要构造器,它的访问级别必须和所属类型的访问级别相同。

默认构造器

public权限的结构体的默认构造器为internal权限,如果需要public权限的构造器,你需要自己提供

上一篇 下一篇

猜你喜欢

热点阅读