来源

 

  1. 访问级别
    1. 访问级别的使用原则
    2. 默认访问级别
    3. 单目标应用程序的访问级别
    4. Framework的访问级别
  2. 访问控制语法
  3. 自定义类型
    1. 元组类型
    2. 函数类型
    3. 枚举类型
    4. 原始值和关联值
    5. 嵌套类型
  4. 子类
  5. 常量、变量、属性、下标
  6. 初始化
  7. 协议
  8. 扩展
  9. 泛型
  10. 类型别名

 

访问控制可以控制哪些代码你可以访问,哪些代码你不能访问。

 

访问级别

Swift 提供了三种不同的访问级别:

  1. Public:可以访问自己模块或应用中源文件里的任何实体,别人也可以访问引入该模块中源文件里的所有实体。通常情况下,某个接口或 Framework 是可以被任何人使用时,你可以将其设置为 public 级别。
  2. Internal:可以访问自己模块或应用中源文件里的任何实体,但是别人不能访问该模块中源文件里的实体。通常情况下,某个接口或 Framework 作为内部结构使用时,你可以将其设置为 internal 级别。
  3. Private:只能在当前源文件中使用的实体,称为私有实体。

Public 为最高级访问级别,Private 为最低级访问级别。

 

访问级别的使用原则

在 Swift 中,访问级别有如下使用原则:

  1. 一个 public 访问级别的变量,不能将它的类型定义为 internal 和 private 的类型。因为变量可以被任何人访问,但是定义它的类型不可以,所以这样就会出现错误。
  2. 函数的访问级别不能高于它的参数、返回类型的访问级别。因为如果函数定义为 public 而参数或者返回类型定义为 internal 或 private,就会出现函数可以被任何人访问,但是它的参数和返回类型不可以,同样会出现错误。

 

默认访问级别

代码中的所有实体,如果你不明确的定义其访问级别,那么它们默认为 internal 级别。

单目标应用程序的访问级别

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

Framework的访问级别

当你开发 Framework 时,就需要把一些实体定义为 public 级别,以便其他人导入该 Framework 后可以正常使用其功能。这些被你定义为 public 的实体,就是这个 Framework 的API。

 

访问控制语法

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

public class SomePublicClass {} 
internal class SomeInternalClass {} 
private class SomePrivateClass {} 
 
public var somePublicVariable = 0 
internal let someInternalConstant = 0 
private func somePrivateFunction() {} 

 

自定义类型

类的访问级别也可以影响到类成员(属性、函数、初始化方法等)的默认访问级别。如果你将类声明为 private 类,那么该类的所有成员的默认访问级别也会成为 private 。如果你将类声明为 public 或者 internal 类型,那么该类的所有成员的访问级别是 internal 。

public class SomePublicClass {          // 显示的 public 类 
    public var somePublicProperty = 0    // 显示的 public 类成员 
    var someInternalProperty = 0         // 隐式的 internal 类成员 
    private func somePrivateMethod() {}  // 显示的 private 类成员 
} 
 
class SomeInternalClass {               // 隐式的 internal 类 
    var someInternalProperty = 0         // 隐式的 internal 类成员 
    private func somePrivateMethod() {}  // 显示的 private 类成员 
} 
 
private class SomePrivateClass {        // 显示的 private 类 
    var somePrivateProperty = 0          // 隐式的 private 类成员 
    func somePrivateMethod() {}          // 隐式的 private 类成员 
} 

 

元组类型

元组的访问级别使用是所有类型的访问级别使用中最为严谨的。比如说,如果你构建一个包含两种不同类型元素的元组,其中一个元素类型的访问级别为 internal,另一个为 private 级别,那么这个元组的访问级别为 private 。也就是说元组的访问级别遵循它里面元组中最低级的访问级别

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

函数类型
函数的访问级别需要根据该函数的参数类型访问级别、返回类型访问级别得出。如果根据参数类型和返回类型得出的函数访问级别不符合上下文,那么就需要明确的声明该函数的访问级别。
 
下面的例子中定义了一个全局函数名为 someFunction ,并且没有明确的声明其访问级别。你也许会认为该函数应该拥有默认的访问级别 internal,但事实并非如此。事实上,如果按下面这种写法,编译器是无法编译通过的:
func someFunction() -> (SomeInternalClass, SomePrivateClass) { 
    // function implementation goes here 
} 

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

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

private func someFunction() -> (SomeInternalClass, SomePrivateClass) { 
    // function implementation goes here 
} 
枚举类型

枚举中成员的访问级别继承自该枚举,你不能为枚举中的成员指定访问级别。

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

public enum CompassPoint { 
    case North 
    case South 
    case East 
    case West 
} 
原始值和关联值

用于枚举定义中的任何原始值,或关联的值类型必须有一个访问级别,至少要高于枚举的访问级别。比如说,你不能在一个 internal 访问级别的枚举中定义 private 级别的原始值类型。 

嵌套类型

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

子类

子类的访问级别可以比父类低,但是不能高于父类的访问级别。比如说,父类的访问级别是 internal ,子类的访问级别就不能声明为 public 。

public class A { 
    private func someMethod() {} 
} 
 
internal class B: A { 
    override internal func someMethod() { // 重写了父类的方法访问级别
        super.someMethod() 
    } 
} 

 

常量、变量、属性、下标

常量、变量、属性不能拥有比它们的类型更高的访问级别。比如说,你定义一个 public 级别的属性,但是它的类型是 private 级别的,这是编译器不允许的。同样,下标也不能拥有比索引类型或返回类型更高的访问级别。
 
如果常量、变量、属性、下标索引的定义类型是 private 级别的,那么它们必须要明确的声明访问级别为 private:
private var privateInstance = SomePrivateClass() 
GetterSetter

常量、变量、属性、下标索引的 Getters 和 Setters 的访问级别继承自它们所属成员的访问级别。

Setter 的访问级别可以低于对应的 Getter 的访问级别,这样就可以控制变量、属性或下标索引的读写权限。在var或subscript定义作用域之前,你可以通过private(set)或internal(set)先为它门的写权限声明一个较低的访问级别。

struct TrackedString { 
    private(set) var numberOfEdits = 0 
    var value: String = "" { 
    didSet { 
        numberOfEdits++ 
    } 
    } 
} 

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

虽然你可以在其他的源文件中实例化该结构体并且获取到numberOfEdits属性的值,但是你不能对其进行赋值。

 

初始化

我们可以给自定义的初始化方法指定访问级别,但是必须要低于或等于它所属类的访问级别。但如果该初始化方法是必须要使用的话,那它的访问级别就必须和所属类的访问级别相同

默认初始化方法

Swift 为结构体、类都提供了一个默认的无参初始化方法,用于给它们的所有属性提供赋值操作,但不会给出具体值。默认初始化方法的访问级别与所属类型的访问级别相同。

注意:如果一个类型被声明为public级别,那么默认的无参初始化方法的访问级别为 internal 。如果你想让无参的初始化方法在其他模块中可以被使用,那么你必须提供一个具有 public 访问级别的无参初始化方法。

结构体的默认成员初始化方法

如果结构体中的任一存储属性的访问级别为 private ,那么它的默认成员初始化方法访问级别就是 private 。尽管如此,结构体的默认无参初始化方法的访问级别依然是 internal 。

如果你想在其他模块中使用该结构体的默认成员初始化方法,那么你需要提供一个访问级别为 public 的默认成员初始化方法。

 

协议

协议中的每一个必须要实现的函数都具有和该协议相同的访问级别。这样才能确保该协议的使用者可以实现它所提供的函数。

注意:如果你定义了一个 public 访问级别的协议,那么实现该协议提供的必要函数也会是public的访问级别。这一点不同于其他类型,比如 public 访问级别的其他类型,他们成员的访问级别为 internal 。

协议继承

如果定义了一个新的协议,并且该协议继承了一个已知的协议,那么新协议拥有的访问级别最高也只和被继承协议的访问级别相同。比如说,你不能定义一个public的协议而去继承一个internal的协议。

 

扩展

如果你扩展了一个public类型,那么你新加的成员应该具有和原始成员一样的默认的 internal 访问级别。

当然你也可以明确声明扩展的访问级别(比如使用 private extension)给该扩展内所有成员指定一个新的默认访问级别。

协议的扩展

如果一个扩展采用了某个协议,那么你就不能对该扩展使用访问级别修饰符来声明了。该扩展中实现协议的方法都会遵循该协议的访问级别。

 

泛型

泛型类型或泛型函数的访问级别遵循泛型类型、函数本身、泛型类型参数三者中访问级别最低的级别。

类型别名

任何被你定义的类型别名都会被视作为不同的类型,这些类型用于访问控制。一个类型别名的访问级别可以低于或等于这个类型的访问级别。比如说,一个private级别的类型别名可以设定给一个public、internal、private的类型,但是一个public级别的类型别名只能设定给一个public级别的类型,不能设定给internal或private的类类型。

注意:这条规则也适用于为满足协议一致性而给相关类型命名别名。

 

2015-03-25

22:08:27

posted on 2015-03-25 22:09  道无涯  阅读(165)  评论(0编辑  收藏  举报