Access Control (访问控制)

Access controlrestricts access to parts of your code from code in other source files and modules. This feature enables you to hide the implementation details of your code, and to specify a preferred interface through which that code can be accessed and used.

访问控制可以限定其他源文件或模块中的代码对你的代码的访问级别。这个特性可以让我们隐藏代码的一些实现细节,并且可以为其他人可以访问和使用的代码提供接口。

You can assign specific access levels to individual types (classes, structures, and enumerations), as well as to properties, methods, initializers, and subscripts belonging to those types. Protocols can be restricted to a certain context, as can global constants, variables, and functions.

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

In addition to offering various levels of access control, Swift reduces the need to specify explicit access control levels by providing default access levels for typical scenarios. Indeed, if you are writing a single-target app, you may not need to specify explicit access control levels at all.

Swift 不仅提供了多种不同的访问级别,还为某些典型场景提供了默认的访问级别,这样就不需要我们在每段代码中都申明显式访问级别。其实,如果只是开发一个单一目标的应用程序,我们完全可以不用显式声明代码的访问级别。

NOTE

The various aspects of your code that can have access control applied to them (properties, types, functions, and so on) are referred to as “entities” in the sections below, for brevity.

为了简单起见,对于代码中可以设置访问级别的特性(属性、基本类型、函数等),在下面的章节中我们会称之为“实体”。

Modules and Source Files (模块和源文件)

Swift’s access control model is based on the concept of modules and source files.

Swift 中的访问控制模型基于模块和源文件这两个概念。

Amoduleis a single unit of code distribution—a framework or application that is built and shipped as a single unit and that can be imported by another module with Swift’simportkeyword.

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

Each build target (such as an app bundle or framework) in Xcode is treated as a separate module in Swift. If you group together aspects of your app’s code as a stand-alone framework—perhaps to encapsulate and reuse that code across multiple applications—then everything you define within that framework will be part of a separate module when it is imported and used within an app, or when it is used within another framework.

在 Swift 中,Xcode 的每个目标(例如框架或应用程序)都被当作独立的模块处理。如果你是为了实现某个通用的功能,或者是为了封装一些常用方法而将代码打包成独立的框架,这个框架就是 Swift 中的一个模块。当它被导入到某个应用程序或者其他框架时,框架内容都将属于这个独立的模块。

Asource fileis a single Swift source code file within a module (in effect, a single file within an app or framework). Although it is common to define individual types in separate source files, a single source file can contain definitions for multiple types, functions, and so on.

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

Access Levels (访问级别)

Swift provides five differentaccess levelsfor entities within your code. These access levels are relative to the source file in which an entity is defined, and also relative to the module that source file belongs to.

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

1. Open accessandpublic accessenable entities to be used within any source file from their defining module, and also in a source file from another module that imports the defining module. You typically use open or public access when specifying the public interface to a framework. The difference between open and public access is described below.

开放访问公开访问可以访问同一模块源文件中的任何实体,在模块外也可以通过导入该模块来访问源文件里的所有实体。通常情况下,框架中的某个接口可以被任何人使用时,你可以将其设置为开放或者公开访问。

2. Internal accessenables entities to be used within any source file from their defining module, but not in any source file outside of that module. You typically use internal access when defining an app’s or a framework’s internal structure.

文件私有访问限制实体只能被所定义的文件内部访问。当需要把这些细节被整个文件使用的时候,使用文件私有访问隐藏了一些特定功能的实现细节。

3. File-private accessrestricts the use of an entity to its own defining source file. Use file-private access to hide the implementation details of a specific piece of functionality when those details are used within an entire file.

内部访问可以访问同一模块源文件中的任何实体,但是不能从模块外访问该模块源文件中的实体。通常情况下,某个接口只在应用程序或框架内部使用时,你可以将其设置为内部访问。

4. Private accessrestricts the use of an entity to the enclosing declaration. Use private access to hide the implementation details of a specific piece of functionality when those details are used only within a single declaration.

私有访问限制实体只能在所定义的作用域内使用。需要把这些细节被整个作用域使用的时候,使用文件私有访问隐藏了一些特定功能的实现细节。

Open access is the highest (least restrictive) access level and private access is the lowest (most restrictive) access level.

开放访问为最高(限制最少)访问级别,私有访问为最低(限制最多)访问级别。

Open access applies only to classes and class members, and it differs from public access as follows:

开放访问只作用于类类型和类的成员,它和公开访问的区别如下:

1. Classes with public access, or any more restrictive access level, can be subclassed only within the module where they’re defined.

公开访问或者其他更严访问级别的类,只能在它们定义的模块内部被继承。

2. Class members with public access, or any more restrictive access level, can be overridden by subclasses only within the module where they’re defined.

开放访问的类,可以在它们定义的模块中被继承,也可以在引用它们的模块中被继承。

3. Open classes can be subclassed within the module where they’re defined, and within any module that imports the module where they’re defined.

开放访问的类成员,可以在它们定义的模块中子类中重写,也可以在引用它们的模块中的子类重写。

4. Open class members can be overridden by subclasses within the module where they’re defined, and within any module that imports the module where they’re defined.

把一个类标记为开放,显式地表明,你认为其他模块中的代码使用此类作为父类,然后你已经设计好了你的类的代码了。

Marking a class as open explicitly indicates that you’ve considered the impact of code from other modules using that class as a superclass, and that you’ve designed your class’s code accordingly.

将类标记为打开明确表示您已经考虑了使用该类作为超类的其他模块的代码的影响,并且您已经相应地设计了类的代码。

Guiding Principle of Access Levels (访问级别基本原则)

Access levels in Swift follow an overall guiding principle:No entity can be defined in terms of another entity that has a lower (more restrictive) access level.

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

For example:

例如:

1. A public variable cannot be defined as having an internal, file-private, or private type, because the type might not be available everywhere that the public variable is used.

一个公开访问级别的变量,其类型的访问级别不能是内部,文件私有或是私有类型的。因为无法保证变量的类型在使用变量的地方也具有访问权限。

2. A function cannot have a higher access level than its parameter types and return type, because the function could be used in situations where its constituent types are not available to the surrounding code.

函数的访问级别不能高于它的参数类型和返回类型的访问级别。因为这样就会出现函数可以在任何地方被访问,但是它的参数类型和返回类型却不可以的情况。

The specific implications of this guiding principle for different aspects of the language are covered in detail below.

关于此原则的各种情况的具体实现,将在下面的细节中体现。

Default Access Levels (默认访问级别)

All entities in your code (with a few specific exceptions, as described later in this chapter) have a default access level of internal if you do not specify an explicit access level yourself. As a result, in many cases you do not need to specify an explicit access level in your code.

如果你不为代码中的实体显式指定访问级别,那么它们默认为internal级别(有一些例外情况,稍后会进行说明)。因此,在大多数情况下,我们不需要显式指定实体的访问级别。

Access Levels for Single-Target Apps (单目标应用程序的访问级别)

When you write a simple single-target app, the code in your app is typically self-contained within the app and does not need to be made available outside of the app’s module. The default access level of internal already matches this requirement. Therefore, you do not need to specify a custom access level. You may, however, want to mark some parts of your code as file private or private in order to hide their implementation details from other code within the app’s module.

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

Access Levels for Frameworks (框架的访问级别)

When you develop a framework, mark the public-facing interface to that framework as open or public so that it can be viewed and accessed by other modules, such as an app that imports the framework. This public-facing interface is the application programming interface (or API) for the framework.

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

NOTE

Any internal implementation details of your framework can still use the default access level of internal, or can be marked as private or file private if you want to hide them from other parts of the framework’s internal code. You need to mark an entity as open or public only if you want it to become part of your framework’s API.

框架依然会使用默认的内部访问级别,也可以指定为文件私有访问或者私有访问级别。当你想把某个实体作为框架的 API 的时候,需显式为其指定开放访问或公开访问级别。

Access Levels for Unit Test Targets (单元测试目标的访问级别)

When you write an app with a unit test target, the code in your app needs to be made available to that module in order to be tested. By default, only entities marked as open or public are accessible to other modules. However, a unit test target can access any internal entity, if you mark the import declaration for a product module with the@testableattribute and compile that product module with testing enabled.

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

Access Control Syntax (访问控制语法)

Define the access level for an entity by placing one of theopen,public,internal,fileprivate, orprivatemodifiers before the entity’s introducer:

通过修饰符open,public,internal,filepart,private来声明实体的访问级别:

public class SomePublicClass{}

internal class SomeInternalClass{}

fileprivate class SomeFilePrivateClass{}

private class SomePrivateClass{}

public var somePublicVariable=0

internal let someInternalConstant=0

fileprivate func someFilePrivateFunction() {}

private func somePrivateFunction() {}

Unless otherwise specified, the default access level is internal, as described inDefault Access Levels. This means thatSomeInternalClassandsomeInternalConstantcan be written without an explicit access-level modifier, and will still have an access level of internal:

除非专门指定,否则实体默认的访问级别为内部访问级别,可以查阅默认访问级别这一节。这意味着在不使用修饰符显式声明访问级别的情况下,SomeInternalClass和someInternalConstant仍然拥有隐式的内部访问级别:

class SomeInternalClass{}// implicitly internal

let someInternalConstant=0// implicitly internal

Custom Types (自定义类型)

If you want to specify an explicit access level for a custom type, do so at the point that you define the type. The new type can then be used wherever its access level permits. For example, if you define a file-private class, that class can only be used as the type of a property, or as a function parameter or return type, in the source file in which the file-private class is defined.

如果想为一个自定义类型指定访问级别,在定义类型时进行指定即可。新类型只能在它的访问级别限制范围内使用。例如,你定义了一个文件私有级别的类,那这个类就只能在定义它的源文件中使用,可以作为属性类型、函数参数类型或者返回类型,等等。

The access control level of a type also affects the default access level of that type’smembers(its properties, methods, initializers, and subscripts). If you define a type’s access level as private or file private, the default access level of its members will also be private or file private. If you define a type’s access level as internal or public (or use the default access level of internal without specifying an access level explicitly), the default access level of the type’s members will be internal.

一个类型的访问级别也会影响到类型成员(属性、方法、构造器、下标)的默认访问级别。如果你将类型指定为私有或者文件私有级别,那么该类型的所有成员的默认访问级别也会变成私有或者文件私有级别。如果你将类型指定为公开或者内部访问级别(或者不明确指定访问级别,而使用默认的内部访问级别),那么该类型的所有成员的默认访问级别将是内部访问。

IMPORTANT

A public type defaults to having internal members, not public members. If you want a type member to be public, you must explicitly mark it as such. This requirement ensures that the public-facing API for a type is something you opt in to publishing, and avoids presenting the internal workings of a type as public API by mistake.

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

public class SomePublicClass{// explicitly public class

public var somePublicProperty=0// explicitly public class member

var someInternalProperty=0// implicitly internal class member

fileprivate func someFilePrivateMethod() {}// explicitly file-private class member

private func somePrivateMethod() {}// explicitly private class member

}

class SomeInternalClass{// implicitly internal class

var someInternalProperty=0// implicitly internal class member

fileprivate func someFilePrivateMethod() {}// explicitly file-private class member

private func somePrivateMethod() {}// explicitly private class member

}

fileprivate class SomeFilePrivateClass{// explicitly file-private class

func someFilePrivate Method() {}// implicitly file-private class member

private func somePrivateMethod() {}// explicitly private class member

}

private class SomePrivateClass{// explicitly private class

func somePrivateMethod() {}// implicitly private class member

}

Tuple Types (元组类型)

The access level for a tuple type is the most restrictive access level of all types used in that tuple. For example, if you compose a tuple from two different types, one with internal access and one with private access, the access level for that compound tuple type will be private.

元组的访问级别将由元组中访问级别最严格的类型来决定。例如,如果你构建了一个包含两种不同类型的元组,其中一个类型为内部访问级别,另一个类型为私有访问级别,那么这个元组的访问级别为私有访问级别。

NOTE

Tuple types do not have a standalone definition in the way that classes, structures, enumerations, and functions do. A tuple type’s access level is deduced automatically when the tuple type is used, and cannot be specified explicitly.

元组不同于类、结构体、枚举、函数那样有单独的定义。元组的访问级别是在它被使用时自动推断出的,而无法明确指定。

Function Types (函数类型)

The access level for a function type is calculated as the most restrictive access level of the function’s parameter types and return type. You must specify the access level explicitly as part of the function’s definition if the function’s calculated access level does not match the contextual default.

函数的访问级别根据访问级别最严格的参数类型或返回类型的访问级别来决定。但是,如果这种访问级别不符合函数定义所在环境的默认访问级别,那么就需要明确地指定该函数的访问级别。

The example below defines a global function calledsomeFunction(), without providing a specific access-level modifier for the function itself. You might expect this function to have the default access level of “internal”, but this is not the case. In fact,someFunction()will not compile as written below:

下面的例子定义了一个名为someFunction()的全局函数,并且没有明确地指定其访问级别。也许你会认为该函数应该拥有默认的访问级别internal,但事实并非如此。事实上,如果按下面这种写法,代码将无法通过编译:

func someFunction() -> (SomeInternalClass,SomePrivateClass) {

  // function implementation goes here

}

The function’s return type is a tuple type composed from two of the custom classes defined above inCustom Types. One of these classes was defined as “internal”, and the other was defined as “private”. Therefore, the overall access level of the compound tuple type is “private” (the minimum access level of the tuple’s constituent types).

我们可以看到,这个函数的返回类型是一个元组,该元组中包含两个自定义的类(可查阅自定义类型)。其中一个类的访问级别是internal,另一个的访问级别是private,所以根据元组访问级别的原则,该元组的访问级别是private(元组的访问级别与元组中访问级别最低的类型一致)。

Because the function’s return type is private, you must mark the function’s overall access level with theprivatemodifier for the function declaration to be valid:

因为该函数返回类型的访问级别是private,所以你必须使用private修饰符,明确指定该函数的访问级别:

private func someFunction() -> (SomeInternalClass,SomePrivateClass) {

// function implementation goes here

}

It is not valid to mark the definition ofsomeFunction()with thepublicorinternalmodifiers, or to use the default setting of internal, because public or internal users of the function might not have appropriate access to the private class used in the function’s return type.

将该函数指定为public或internal,或者使用默认的访问级别internal都是错误的,因为如果把该函数当做public或internal级别来使用的话,可能会无法访问private级别的返回值。

Enumeration Types (枚举类型)

The individual cases of an enumeration automatically receive the same access level as the enumeration they belong to. You cannot specify a different access level for individual enumeration cases.

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

In the example below, theCompassPointenumeration has an explicit access level of “public”. The enumeration casesnorth,south,east, andwesttherefore also have an access level of “public”:

比如下面的例子,枚举CompassPoint被明确指定为public级别,那么它的成员North、South、East、West的访问级别同样也是public:

public enum CompassPoint{

  case north

  case south

  case east

  case west

}

Raw Values and Associated Values (原始值和关联值)

The types used for any raw values or associated values in an enumeration definition must have an access level at least as high as the enumeration’s access level. You cannot use aprivatetype as the raw-value type of an enumeration with aninternalaccess level, for example.

枚举定义中的任何原始值或关联值的类型的访问级别至少不能低于枚举类型的访问级别。例如,你不能在一个internal访问级别的枚举中定义private级别的原始值类型。

Nested Types (嵌套类型)

Nested types defined within a private type have an automatic access level of private. Nested types defined within a file-private type have an automatic access level of file private. Nested types defined within a public type or an internal type have an automatic access level of internal. If you want a nested type within a public type to be publicly available, you must explicitly declare the nested type as public.

如果在private级别的类型中定义嵌套类型,那么该嵌套类型就自动拥有private访问级别。如果在public或者internal级别的类型中定义嵌套类型,那么该嵌套类型自动拥有internal访问级别。如果想让嵌套类型拥有public访问级别,那么需要明确指定该嵌套类型的访问级别。

Subclassing (子类)

You can subclass any class that can be accessed in the current access context. A subclass cannot have a higher access level than its superclass—for example, you cannot write a public subclass of an internal superclass.

子类的访问级别不得高于父类的访问级别。例如,父类的访问级别是internal,子类的访问级别就不能是public。

In addition, you can override any class member (method, property, initializer, or subscript) that is visible in a certain access context.

此外,你可以在符合当前访问级别的条件下重写任意类成员(方法、属性、构造器、下标等)。

An override can make an inherited class member more accessible than its superclass version. In the example below, classAis a public class with a file-private method calledsomeMethod(). ClassBis a subclass ofA, with a reduced access level of “internal”. Nonetheless, classBprovides an override ofsomeMethod()with an access level of “internal”, which ishigherthan the original implementation ofsomeMethod():

可以通过重写为继承来的类成员提供更高的访问级别。下面的例子中,类A的访问级别是public,它包含一个方法someMethod(),访问级别为private。类B继承自类A,访问级别为internal,但是在类B中重写了类A中访问级别为private的方法someMethod(),并重新指定为internal级别。通过这种方式,我们就可以将某类中private级别的类成员重新指定为更高的访问级别,以便其他人使用:

public class A{

  fileprivate func someMethod() {}

}

internal class B:A{

  override internal func someMethod() {}

}

It is even valid for a subclass member to call a superclass member that has lower access permissions than the subclass member, as long as the call to the superclass’s member takes place within an allowed access level context (that is, within the same source file as the superclass for a file-private member call, or within the same module as the superclass for an internal member call):

我们甚至可以在子类中,用子类成员去访问访问级别更低的父类成员,只要这一操作在相应访问级别的限制范围内(也就是说,在同一源文件中访问父类private级别的成员,在同一模块内访问父类internal级别的成员):

public class A{

  fileprivate func someMethod() {}

}

internal class B:A{

  override internal func someMethod() {

  super.someMethod()

}

}

Because superclassAand subclassBare defined in the same source file, it is valid for theBimplementation ofsomeMethod()to callsuper.someMethod().

因为父类A和子类B定义在同一个源文件中,所以在子类B可以在重写的someMethod()方法中调用super.someMethod()。

Constants, Variables, Properties, and Subscripts (常量、变量、属性、下标)

A constant, variable, or property cannot be more public than its type. It is not valid to write a public property with a private type, for example. Similarly, a subscript cannot be more public than either its index type or return type.

常量、变量、属性不能拥有比它们的类型更高的访问级别。例如,你不能定义一个public级别的属性,但是它的类型却是private级别的。同样,下标也不能拥有比索引类型或返回类型更高的访问级别。

If a constant, variable, property, or subscript makes use of a private type, the constant, variable, property, or subscript must also be marked asprivate:

如果常量、变量、属性、下标的类型是private级别的,那么它们必须明确指定访问级别为private:

private var privateInstance=SomePrivateClass()

Getters and Setters (Getter 和 Setter)

Getters and setters for constants, variables, properties, and subscripts automatically receive the same access level as the constant, variable, property, or subscript they belong to.

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

You can give a setter aloweraccess level than its corresponding getter, to restrict the read-write scope of that variable, property, or subscript. You assign a lower access level by writingfileprivate(set),private(set), orinternal(set)before thevarorsubscriptintroducer.

Setter的访问级别可以低于对应的Getter的访问级别,这样就可以控制变量、属性或下标的读写权限。在var或subscript关键字之前,你可以通过fileprivate(set),private(set)或internal(set)为它们的写入权限指定更低的访问级别。

NOTE

This rule applies to stored properties as well as computed properties. Even though you do not write an explicit getter and setter for a stored property, Swift still synthesizes an implicit getter and setter for you to provide access to the stored property’s backing storage. Usefileprivate(set),private(set), andinternal(set)to change the access level of this synthesized setter in exactly the same way as for an explicit setter in a computed property.

这个规则同时适用于存储型属性和计算型属性。即使你不明确指定存储型属性的Getter和Setter,Swift 也会隐式地为其创建Getter和Setter,用于访问该属性的后备存储。使用fileprivate(set),private(set)和internal(set)可以改变Setter的访问级别,这对计算型属性也同样适用。

The example below defines a structure calledTrackedString, which keeps track of the number of times a string property is modified:

下面的例子中定义了一个名为TrackedString的结构体,它记录了value属性被修改的次数:

struct TrackedString{

  private (set)varnumberOfEdits=0

  var value:String=""{

  didSet{

    numberOfEdits+=1

  }

}

}

TheTrackedStringstructure defines a stored string property calledvalue, with an initial value of""(an empty string). The structure also defines a stored integer property callednumberOfEdits, which is used to track the number of times thatvalueis modified. This modification tracking is implemented with adidSetproperty observer on thevalueproperty, which incrementsnumberOfEditsevery time thevalueproperty is set to a new value.

TrackedString结构体定义了一个用于存储String值的属性value,并将初始值设为""(一个空字符串)。该结构体还定义了另一个用于存储Int值的属性numberOfEdits,它用于记录属性value被修改的次数。这个功能通过属性value的didSet观察器实现,每当给value赋新值时就会调用didSet方法,然后将numberOfEdits的值加一。

TheTrackedStringstructure and thevalueproperty do not provide an explicit access-level modifier, and so they both receive the default access level of internal. However, the access level for thenumberOfEditsproperty is marked with aprivate(set)modifier to indicate that the property’s getter still has the default access level of internal, but the property is settable only from within code that’s part of theTrackedStringstructure. This enablesTrackedStringto modify thenumberOfEditsproperty internally, but to present the property as a read-only property when it is used outside the structure’s definition—including any extensions toTrackedString.

结构体TrackedString和它的属性value均没有显式指定访问级别,所以它们都拥有默认的访问级别internal。但是该结构体的numberOfEdits属性使用了private(set)修饰符,这意味着numberOfEdits属性只能在定义该结构体的源文件中赋值。numberOfEdits属性的Getter依然是默认的访问级别internal,但是Setter的访问级别是private,这表示该属性只有在当前的源文件中是可读写的,而在当前源文件所属的模块中只是一个可读的属性。

If you create aTrackedStringinstance and modify its string value a few times, you can see thenumberOfEditsproperty value update to match the number of modifications:

如果你实例化TrackedString结构体,并多次对value属性的值进行修改,你就会看到numberOfEdits的值会随着修改次数而变化:

var stringToEdit=TrackedString()

stringToEdit.value="This string will be tracked."

stringToEdit.value+=" This edit will increment numberOfEdits."

stringToEdit.value+=" So will this one."

print("The number of edits is\(stringToEdit.numberOfEdits)")

// Prints "The number of edits is 3"

Although you can query the current value of thenumberOfEditsproperty from within another source file, you cannotmodifythe property from another source file. This restriction protects the implementation details of theTrackedStringedit-tracking functionality, while still providing convenient access to an aspect of that functionality.

虽然你可以在其他的源文件中实例化该结构体并且获取到numberOfEdits属性的值,但是你不能对其进行赋值。这一限制保护了该记录功能的实现细节,同时还提供了方便的访问方式。

Note that you can assign an explicit access level for both a getter and a setter if required. The example below shows a version of theTrackedStringstructure in which the structure is defined with an explicit access level of public. The structure’s members (including thenumberOfEditsproperty) therefore have an internal access level by default. You can make the structure’snumberOfEditsproperty getter public, and its property setter private, by combining thepublicandprivate(set)access-level modifiers:

你可以在必要时为Getter和Setter显式指定访问级别。下面的例子将TrackedString结构体明确指定为了public访问级别。结构体的成员(包括numberOfEdits属性)拥有默认的访问级别internal。你可以结合public和private(set)修饰符把结构体中的numberOfEdits属性的Getter的访问级别设置为public,而Setter的访问级别设置为private:

public structTrackedString{

public private(set)varnumberOfEdits=0

public var value:String=""{

didSet{

numberOfEdits+=1

}

}

public init() {}

}

Initializers (构造器)

Custom initializers can be assigned an access level less than or equal to the type that they initialize. The only exception is for required initializers (as defined inRequired Initializers). A required initializer must have the same access level as the class it belongs to.

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

As with function and method parameters, the types of an initializer’s parameters cannot be more private than the initializer’s own access level.

如同函数或方法的参数,构造器参数的访问级别也不能低于构造器本身的访问级别。

Default Initializers (默认构造器)

As described inDefault Initializers, Swift automatically provides adefault initializerwithout any arguments for any structure or base class that provides default values for all of its properties and does not provide at least one initializer itself.

默认构造器所述,Swift 会为结构体和类提供一个默认的无参数的构造器,只要它们为所有存储型属性设置了默认初始值,并且未提供自定义的构造器。

A default initializer has the same access level as the type it initializes, unless that type is defined aspublic. For a type that is defined aspublic, the default initializer is considered internal. If you want a public type to be initializable with a no-argument initializer when used in another module, you must explicitly provide a public no-argument initializer yourself as part of the type’s definition.

默认构造器的访问级别与所属类型的访问级别相同,除非类型的访问级别是public。如果一个类型被指定为public级别,那么默认构造器的访问级别将为internal。如果你希望一个public级别的类型也能在其他模块中使用这种无参数的默认构造器,你只能自己提供一个public访问级别的无参数构造器。

Default Memberwise Initializers for Structure Types (结构体默认的成员逐一构造器)

The default memberwise initializer for a structure type is considered private if any of the structure’s stored properties are private. Likewise, if any of the structure’s stored properties are file private, the initializer is file private. Otherwise, the initializer has an access level of internal.

如果结构体中任意存储型属性的访问级别为private,那么该结构体默认的成员逐一构造器的访问级别就是private。否则,这种构造器的访问级别依然是internal。

As with the default initializer above, if you want a public structure type to be initializable with a memberwise initializer when used in another module, you must provide a public memberwise initializer yourself as part of the type’s definition.

如同前面提到的默认构造器,如果你希望一个public级别的结构体也能在其他模块中使用其默认的成员逐一构造器,你依然只能自己提供一个public访问级别的成员逐一构造器。

Protocols (协议)

If you want to assign an explicit access level to a protocol type, do so at the point that you define the protocol. This enables you to create protocols that can only be adopted within a certain access context.

如果想为一个协议类型明确地指定访问级别,在定义协议时指定即可。这将限制该协议只能在适当的访问级别范围内被采纳。

The access level of each requirement within a protocol definition is automatically set to the same access level as the protocol. You cannot set a protocol requirement to a different access level than the protocol it supports. This ensures that all of the protocol’s requirements will be visible on any type that adopts the protocol.

协议中的每一个要求都具有和该协议相同的访问级别。你不能将协议中的要求设置为其他访问级别。这样才能确保该协议的所有要求对于任意采纳者都将可用。

NOTE

If you define a public protocol, the protocol’s requirements require a public access level for those requirements when they are implemented. This behavior is different from other types, where a public type definition implies an access level of internal for the type’s members.

如果你定义了一个public访问级别的协议,那么该协议的所有实现也会是public访问级别。这一点不同于其他类型,例如,当类型是public访问级别时,其成员的访问级别却只是internal。

Protocol Inheritance (协议继承)

If you define a new protocol that inherits from an existing protocol, the new protocol can have at most the same access level as the protocol it inherits from. You cannot write a public protocol that inherits from an internal protocol, for example.

如果定义了一个继承自其他协议的新协议,那么新协议拥有的访问级别最高也只能和被继承协议的访问级别相同。例如,你不能将继承自internal协议的新协议定义为public协议。

Protocol Conformance (协议一致性)

A type can conform to a protocol with a lower access level than the type itself. For example, you can define a public type that can be used in other modules, but whose conformance to an internal protocol can only be used within the internal protocol’s defining module.

一个类型可以采纳比自身访问级别低的协议。例如,你可以定义一个public级别的类型,它可以在其他模块中使用,同时它也可以采纳一个internal级别的协议,但是只能在该协议所在的模块中作为符合该协议的类型使用。

The context in which a type conforms to a particular protocol is the minimum of the type’s access level and the protocol’s access level. If a type is public, but a protocol it conforms to is internal, the type’s conformance to that protocol is also internal.

采纳了协议的类型的访问级别取它本身和所采纳协议两者间最低的访问级别。也就是说如果一个类型是public级别,采纳的协议是internal级别,那么采纳了这个协议后,该类型作为符合协议的类型时,其访问级别也是internal。

When you write or extend a type to conform to a protocol, you must ensure that the type’s implementation of each protocol requirement has at least the same access level as the type’s conformance to that protocol. For example, if a public type conforms to an internal protocol, the type’s implementation of each protocol requirement must be at least “internal”.

如果你采纳了协议,那么实现了协议的所有要求后,你必须确保这些实现的访问级别不能低于协议的访问级别。例如,一个public级别的类型,采纳了internal级别的协议,那么协议的实现至少也得是internal级别。

NOTE

In Swift, as in Objective-C, protocol conformance is global—it is not possible for a type to conform to a protocol in two different ways within the same program.

Swift 和 Objective-C 一样,协议的一致性是全局的,也就是说,在同一程序中,一个类型不可能用两种不同的方式实现同一个协议。

Extensions (扩展)

You can extend a class, structure, or enumeration in any access context in which the class, structure, or enumeration is available. Any type members added in an extension have the same default access level as type members declared in the original type being extended. If you extend a public or internal type, any new type members you add have a default access level of internal. If you extend a file-private type, any new type members you add have a default access level of file private. If you extend a private type, any new type members you add have a default access level of private.

你可以在访问级别允许的情况下对类、结构体、枚举进行扩展。扩展成员具有和原始类型成员一致的访问级别。例如,你扩展了一个public或者internal类型,扩展中的成员具有默认的internal访问级别,和原始类型中的成员一致 。如果你扩展了一个private类型,扩展成员则拥有默认的private访问级别。

Alternatively, you can mark an extension with an explicit access-level modifier (for example,private extension) to set a new default access level for all members defined within the extension. This new default can still be overridden within the extension for individual type members.

或者,你可以明确指定扩展的访问级别(例如,private extension),从而给该扩展中的所有成员指定一个新的默认访问级别。这个新的默认访问级别仍然可以被单独指定的访问级别所覆盖。

Adding Protocol Conformance with an Extension (通过扩展添加协议一致性)

You cannot provide an explicit access-level modifier for an extension if you are using that extension to add protocol conformance. Instead, the protocol’s own access level is used to provide the default access level for each protocol requirement implementation within the extension.

如果你通过扩展来采纳协议,那么你就不能显式指定该扩展的访问级别了。协议拥有相应的访问级别,并会为该扩展中所有协议要求的实现提供默认的访问级别。

Generics (泛型)

The access level for a generic type or generic function is the minimum of the access level of the generic type or function itself and the access level of any type constraints on its type parameters.

泛型类型或泛型函数的访问级别取决于泛型类型或泛型函数本身的访问级别,还需结合类型参数的类型约束的访问级别,根据这些访问级别中的最低访问级别来确定。

Type Aliases (类型别名)

Any type aliases you define are treated as distinct types for the purposes of access control. A type alias can have an access level less than or equal to the access level of the type it aliases. For example, a private type alias can alias a private, file-private, internal, public, or open type, but a public type alias cannot alias an internal, file-private, or private type.

你定义的任何类型别名都会被当作不同的类型,以便于进行访问控制。类型别名的访问级别不可高于其表示的类型的访问级别。例如,private级别的类型别名可以作为private,file-private,internal,public或者open类型的别名,但是public级别的类型别名只能作为public类型的别名,不能作为internal,file-private,或private类型的别名。

NOTE

This rule also applies to type aliases for associated types used to satisfy protocol conformances.

这条规则也适用于为满足协议一致性而将类型别名用于关联类型的情况。

推荐阅读更多精彩内容