28.2. 访问级别

Swift 为代码中的实体提供了五种不同的访问级别。这些访问级别不仅与源文件中定义的实体相关,同时也与源文件所属的模块相关。

  • openpublic 级别可以让实体被同一模块源文件中的所有实体访问,在模块外也可以通过导入该模块来访问源文件里的所有实体。通常情况下,你会使用 open 或 public 级别来指定框架的外部接口。open 和 public 的区别在后面会提到。
  • internal 级别让实体被同一模块源文件中的任何实体访问,但是不能被模块外的实体访问。通常情况下,如果某个接口只在应用程序或框架内部使用,就可以将其设置为 internal 级别。
  • fileprivate 限制实体只能在其定义的文件内部访问。如果功能的部分实现细节只需要在文件内使用时,可以使用 fileprivate 来将其隐藏。
  • private 限制实体只能在其定义的作用域,以及同一文件内的 extension 访问。如果功能的部分细节只需要在当前作用域内使用时,可以使用 private 来将其隐藏。

open 为最高访问级别(限制最少),private 为最低访问级别(限制最多)。

open 只能作用于类和类的成员,它和 public 的区别主要在于 open 限定的类和成员能够在模块外能被继承和重写,在下面的子类这一节中有详解。将类的访问级别显式指定为 open 表明你已经设计好了类的代码,并且充分考虑过这个类在其他模块中用作父类时的影响。

访问级别基本原则

Swift 中的访问级别遵循一个基本原则:实体不能定义在具有更低访问级别(更严格)的实体中

例如:

  • 一个 public 的变量,其类型的访问级别不能是 internal,fileprivate 或是 private。因为无法保证变量的类型在使用变量的地方也具有访问权限。
  • 函数的访问级别不能高于它的参数类型和返回类型的访问级别。因为这样就会出现函数可以在任何地方被访问,但是它的参数类型和返回类型却不可以的情况。

关于此原则在各种情况下的具体表现,将在下文有所体现。

默认访问级别

你代码中所有的实体,如果你不显式的指定它们的访问级别,那么它们将都有一个 internal 的默认访问级别,(有一些例外情况,本文稍后会有说明)。因此,多数情况下你不需要显示指定实体的访问级别。

单 target 应用程序的访问级别

当你编写一个单 target 应用程序时,应用的所有功能都是为该应用服务,而不需要提供给其他应用或者模块使用,所以你不需要明确设置访问级别,使用默认的访问级别 internal 即可。但是,你也可以使用 fileprivateprivate 访问级别,用于隐藏一些功能的实现细节。

框架的访问级别

当你开发框架时,就需要把一些对外的接口定义为 open 或 public 访问级别,以便使用者导入该框架后可以正常使用其功能。这些被你定义为对外的接口,就是这个框架的 API。

注意

框架的内部实现仍然可以使用默认的访问级别 internal,当你需要对框架内部其它部分隐藏细节时可以使用 privatefileprivate。对于框架的对外 API 部分,你就需要将它们设置为 openpublic 了。

单元测试 target 的访问级别

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