Swift - Access Control

访问控制模型是基于 Modules & Source Files
作用:隐藏代码的实现,指定接口能够被访问和使用

Module

  • 是单一的代码分配单元 - 一个框架或应用程序会作为独立的单元构建和发布并且可以使用 Swift 的 import 关键字导入到另一个 module
  • Swift 的 module 相当于每一个 Target (app bundle OR framework)

Source File

  • 在一个 module 中的一个 Swift 源代码文件
  • 通常每一个类型分配在单独源文件,一个源文件也可以包括定义多个类型、方法等等

五种访问等级

从高到低:open / public / internal / fileprivate / private

Open & Public

  • 在被定义的 module 中使用
  • 在其他 module 中使用,imports 被定义的 module
  • 指定 Framework 公共接口,使用 open 和 public 修饰

Internal

  • 在被定义的 module 中使用
  • 在 app 或 Framework 内部结构时使用

File-private

  • 在被定义的源文件中使用

Private

  • 定义的范围内 + 同文件内的 extension 中使用

Open 只能用于类和类成员,以下几点不同于 Public

  • < Public(类),只能在所在的 module 被子类化
  • < Public(类成员),只能在所在的 module 被子类重写
  • Open(类)能够在所在的 module 中被子类化,或者在任何已 import module 的 module 中被子类化
  • Open(类成员)能够在所在的 module 中被子类化,或者在任何已 import module 的 module 中被子类重写

✨访问权限的原则

实体不能被另外一个低访问权限的实体定义
eg:

  • 一个 public 变量不能被定义有一个 internal / file-private / private 类型定义,因为类型也许不能在 public 变量使用时有效
  • 方法 level !> 参数 level & return level

默认访问等级 - internal

Unit Test Targets

除了标记 Open 和 Public,能够访问任何 internal 实体的方式:在 import module 前加 @testable

Frameworks

open / public 修饰 API

自定义类型

  • 如果定义类型为 private / file-private,默认成员的访问等级也是 private / file-private
  • 如果定义类型为 internal / public,默认成员的访问等级是 Internal(如果需要,用 public 修饰,提供选择性发布,避免将内部类型作为 API)
fileprivate class SomeFilePrivateClass {
    func someFilePrivateMethod() {}
    private func somePrivateMethod() {} 
}

元祖类型

整个元祖类型的访问权限,决定于元祖中所有类型的最低访问权限,不能特指访问权限

方法类型

方法类型的访问权限,决定于方法参数类型和返回值类型的最低访问权限

func someFunction() -> (SomeInternalClass, SomePrivateClass) {
    // function implementation goes here
}
// 也许会期望方法的默认访问权限为 internal,但是实际上取决于元祖类型 
// 并且在这里不能用 public 和 internal 修饰改方法

枚举类型

  • 不能为独立的枚举 case 指定不同的访问权限
  • 独立的枚举 case 自动为枚举类型的相同访问权限
  • 原生值 和 关联值 必须至少和枚举有相同的访问等级

嵌套类型

  • 嵌套类型在一个 private 有一个自动 private 访问类型
  • 嵌套类型在一个 file-private 类型中自动有 file-private 访问类型
  • 嵌套类型在在一个 public OR internal 类型中自动有 internal 中
  • 如果需要 public 类型就显式指定

子类化

  • 一个子类不能有高于父类的访问权限
  • 重写可以让继承的类成员比其父类更容易访问
public class A {
    fileprivate func someMethod() {}
}

internal class B: A {
    override internal func someMethod(){
      super.someMethod()
  }
}

常量、变量、属性和下标

  • 不能比它的类型还高级
  • 下标不能比它的索引类型和返回值更高级
private var privateInstance = SomePrivateClass()

Setter and Getter

  • setter / getter 自动接收 常量、变量、属性、下标的访问等级
  • fileprivate(set) / private(set) / internal(set) 修饰变量 OR 下标,这个规则应用于存储属性和计算属性
struct TrackedString {
// setter: private ; getter: internal
    private(set) var numberOfEdits = 0
    var value: String = "" {
          didSet {
              numberOfEdit += 1
          }
    }
}
public struct TrackedString {
    // 默认是 getter internal;此时设置为 getter public
    public private(set) var numberOfEdits = 0
    public var value: String = "" {
          didSet {
                numberOfEdits += 1
          }
    }
    public init() {}
}

初始化

  • 自定义初始化器能够被定义低于或等于他们的类型
  • 除了 Required 初始化器必须和类有相同的访问等级
  • 初始化器的参数不能低于初始化器的本身访问等级

默认初始化器

  • Swift 自动提供一个没有任何参数的默认初始化,为结构体和类的所有属性提供默认值,但没有提供初始化本身的方法
  • 默认的初始化器有和类型相同的访问等级,除了public 的类型

结构体类型的默认 Memberwise 初始化器

  • 如果结构体的所有存储属性是 private, 结构体类型也是 private
  • 如果结构体的所有存储属性时 file-private,结构体类型也是 file-private
  • 如果需要 public 结构体类型能够在另外的 module 中使用,必须提供一个 public memberwise 初始化器

协议

-requirement 自动设置与协议相同的访问等级,并且不能设置与其不同的等级,以确保所有 requirement 能够有效适用任何遵循该协议的类型

协议继承

最高访问权限为父协议的等级

协议遵循

  • 一个类型能够遵循一个低于它访问等级的协议
  • 一个类型遵循一个协议,访问等级为协议和类型的最低访问等级
  • 一个类型遵循一个协议必须确保每一个 requirement 至少有和协议相同的访问等级

遵循协议是全局的:一个类型不能以两种不同的方式遵循一个协议

Extensions

class / structure / enumeration

  • 新扩展的类成员和被扩展类型的访问等级一致
    extension public / internal -> type member internal
    extension private -> type member private
    extension file-private -> type member file-private

  • 可以为所有在 extension 的成员定义一个新的等级,同样也可以针对单个成员重写
    eg: private extension

  • 如果使用了 extension 添加协议遵循,不能提供一个显式的访问等级修饰一个扩展

在 Extension 中的私有成员

  • 声明一个私有成员在初始声明中,能在同个文件的 extension 中访问
  • 在 extension 中声明私有成员,其他来自同一文件的其他 extension 中访问
  • 在 extension 中声明私有成员,能够被来自同个文件的初始声明中访问

泛型

泛型类型 / 泛型方法 level = minimum (泛型类型 / 泛型方法,类型参数上的类型约束)

类型别名

类型别名 level <= 类型 level

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,546评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,224评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,911评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,737评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,753评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,598评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,338评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,249评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,696评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,888评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,013评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,731评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,348评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,929评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,048评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,203评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,960评论 2 355

推荐阅读更多精彩内容