//访问控制
import UIKit
/*访问控制(Access Control)
1.访问控制可以限定其他源文件或模块中的代码对你的代码的访问级别。这个特性可以让我们隐藏代码的一些实现细节,并且可以为其他人可以访问和使用的代码提供接口
2.你可以明确地给单个类型(类、结构体、枚举)设置访问级别,也可以给这些类型的属性、方法、构造器、下标等设置访问级别
3.协议也可以被限定在一定的范围内使用,包括协议里的全局常量、变量和函数
模块:
1.模块指的是独立的代码单元,框架或应用程序会作为一个独立的模块来构建和发布。
2.在 Swift 中,一个模块可以使用 import 关键字导入另外一个模块
3.在 Swift 中,Xcode 的每个 target(例如框架或应用程序)都被当作独立的模块处理。如果你是为了实现某个通用的功能,或者是为了封装一些常用方法而将代码打包成独立的框架,这个框架就是 Swift 中的一个模块。当它被导入到某个应用程序或者其他框架时,框架内容都将属于这个独立的模块
源文件:源文件就是 Swift 中的源代码文件,它通常属于一个模块,即一个应用程序或者框架
访问级别:
1.Swift 为代码中的实体提供了三种不同的访问级别。这些访问级别不仅与源文件中定义的实体相关,同时也与源文件所属的模块相关。
1.public:可以访问同一模块源文件中的任何实体,在模块外也可以通过导入该模块来访问源文件里的所有实体。通常情况下,框架中的某个接口可以被任何人使用时,你可以将其设置为 public 级别。
2.internal:可以访问同一模块源文件中的任何实体,但是不能从模块外访问该模块源文件中的实体。通常情况下,某个接口只在应用程序或框架内部使用时,你可以将其设置为 internal 级别。
3.private:限制实体只能在所在的源文件内部使用。使用 private 级别可以隐藏某些功能的实现细节。
4.public 为最高(限制最少)访问级别,private 为最低(限制最多)访问级别
访问级别基本原则:
1.访问级别遵循一个基本原则:不可以在某个实体中定义访问级别更高的实体
2.默认访问级别:如果你不为代码中的实体显式指定访问级别,那么它们默认为 internal 级别
单 target 应用程序的访问级别:
当你编写一个单 target 应用程序时,应用的所有功能都是为该应用服务,而不需要提供给其他应用或者模块使用,所以我们不需要明确设置访问级别,使用默认的访问级别 internal 即可。但是,你也可以使用 private 级别,用于隐藏一些功能的实现细节。
框架的访问级别:
当你开发框架时,就需要把一些对外的接口定义为 public 级别,以便使用者导入该框架后可以正常使用其功能。这些被你定义为 public 的接口,就是这个框架的 API
单元测试 target 的访问级别:
当你的应用程序包含单元测试 target 时,为了测试,测试模块需要访问应用程序模块中的代码。默认情况下只有 public 级别的实体才可以被其他模块访问。然而,如果在导入应用程序模块的语句前使用 @testable 特性,然后在允许测试的编译设置(Build Options -> Enable Testability)下编译这个应用程序模块,单元测试 target 就可以访问应用程序模块中所有 internal 级别的实体
类型访问级别:
1.一个类型的访问级别也会影响到类型成员(属性、方法、构造器、下标)的默认访问级别。如果你将类型指定为 private 级别,那么该类型的所有成员的默认访问级别也会变成 private
2.一个 public 类型的所有成员的访问级别默认为 internal 级别,而不是 public 级别。如果你想将某个成员指定为 public 级别,那么你必须显式指定
元组类型:元组的访问级别将由元组中访问级别最严格的类型来决定,元组不同于类、结构体、枚举、函数那样有单独的定义。元组的访问级别是在它被使用时自动推断出的,而无法明确指定
函数类型:函数的访问级别根据访问级别最严格的参数类型或返回类型的访问级别来决定。但是,如果这种访问级别不符合函数定义所在环境的默认访问级别,那么就需要明确地指定该函数的访问级别
枚举类型:枚举成员的访问级别和该枚举类型相同,你不能为枚举成员单独指定不同的访问级别,枚举定义中的任何原始值或关联值的类型的访问级别至少不能低于枚举类型的访问级别。例如,你不能在一个 internal 访问级别的枚举中定义 private 级别的原始值类型
嵌套类型:如果在 private 级别的类型中定义嵌套类型,那么该嵌套类型就自动拥有 private 访问级别。如果在 public 或者 internal 级别的类型中定义嵌套类型,那么该嵌套类型自动拥有 internal 访问级别。如果想让嵌套类型拥有 public 访问级别,那么需要明确指定该嵌套类型的访问级别
子类:子类的访问级别不得高于父类的访问级别,可以在符合当前访问级别的条件下重写任意类成员,可以通过重写为继承来的类成员提供更高的访问级别
常量、变量、属性、下标:
1.常量、变量、属性不能拥有比它们的类型更高的访问级别,如果常量、变量、属性、下标的类型是 private 级别的,那么它们必须明确指定访问级别为 private
2.常量、变量、属性、下标的 Getters 和 Setters 的访问级别和它们所属类型的访问级别相同
3.Setter 的访问级别可以低于对应的 Getter 的访问级别,这样就可以控制变量、属性或下标的读写权限。在 var 或 subscript 关键字之前,你可以通过 private(set) 或 internal(set) 为它们的写入权限指定更低的访问级别,存储型属性有默认的Getter和Setter
4.可以在必要时为 Getter 和 Setter 显式指定访问级别
构造器:自定义构造器的访问级别可以低于或等于其所属类型的访问级别。唯一的例外是必要构造器,它的访问级别必须和所属类型的访问级别相同,如同函数或方法的参数,构造器参数的访问级别也不能低于构造器本身的访问级别
默认构造器:默认构造器的访问级别与所属类型的访问级别相同,除非类型的访问级别是 public。如果一个类型被指定为 public 级别,那么默认构造器的访问级别将为 internal。如果你希望一个 public 级别的类型也能在其他模块中使用这种无参数的默认构造器,你只能自己提供一个 public 访问级别的无参数构造器
结构体默认的成员逐一构造器:如果结构体中任意存储型属性的访问级别为 private,那么该结构体默认的成员逐一构造器的访问级别就是 private。否则,这种构造器的访问级别依然是 internal。如同前面提到的默认构造器,如果你希望一个 public 级别的结构体也能在其他模块中使用其默认的成员逐一构造器,你依然只能自己提供一个 public 访问级别的成员逐一构造器
协议:
1.协议中的每一个要求都具有和该协议相同的访问级别。你不能将协议中的要求设置为其他访问级别。这样才能确保该协议的所有要求对于任意采纳者都将可用
2.继承来的协议的访问级别低于或等于父协议的访问级别
3.协议一致性:一个类型可以采纳比自身访问级别低的协议,采纳了协议的类型的访问级别取它本身和所采纳协议两者间最低的访问级别
扩展:
1.可以在访问级别允许的情况下对类、结构体、枚举进行扩展。扩展成员具有和原始类型成员一致的访问级别
2.可以明确指定扩展的访问级别(例如,private extension),从而给该扩展中的所有成员指定一个新的默认访问级别。这个新的默认访问级别仍然可以被单独指定的访问级别所覆盖
泛型:泛型类型或泛型函数的访问级别取决于泛型类型或泛型函数本身的访问级别,还需结合类型参数的类型约束的访问级别,根据这些访问级别中的最低访问级别来确定
类型别名:你定义的任何类型别名都会被当作不同的类型,以便于进行访问控制。类型别名的访问级别不可高于其表示的类型的访问级别
*/
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 类成员
}
//=======
public class A {
private func someMethod() {}
}
internal class B: A {
override internal func someMethod() {} //在符合当前访问级别的条件下,通过重写为继承来的类成员提供更高的访问级别
}
//=======
struct TrackedString {
private(set) var numberOfEdits = 0 //可以在其他的源文件中实例化该结构体并且获取到 numberOfEdits 属性的值,但是你不能对其进行赋值
var value: String = "" {
didSet {
numberOfEdits++
}
}
}
public struct TrackedString1 {
public private(set) var numberOfEdits = 0 //在必要时为Getter和Setter显式指定访问级别,结合 public 和 private(set) 修饰符把结构体中的 numberOfEdits 属性的 Getter 的访问级别设置为 public,而 Setter 的访问级别设置为 private
public var value: String = "" {
didSet {
numberOfEdits++
}
}
public init() {}
}