swift简单总结(三十四)—— 访问控制

版本记录

版本号 时间
V1.0 2017.08.01

前言

我是swift2.0的时候开始接触的,记得那时候还不是很稳定,公司的项目也都是用oc做的,并不对swift很重视,我自己学了一段时间,到现在swift3.0+已经出来了,自己平时也不写,忘记的也差不多了,正好项目这段时间已经上线了,不是很忙,我就可以每天总结一点了,希望对自己对大家有所帮助。在总结的时候我会对比oc进行说明,有代码的我会给出相关比对代码。
1. swift简单总结(一)—— 数据简单值和类型转换
2. swift简单总结(二)—— 简单值和控制流
3. swift简单总结(三)—— 循环控制和函数
4. swift简单总结(四)—— 函数和类
5. swift简单总结(五)—— 枚举和结构体
6. swift简单总结(六)—— 协议扩展与泛型
7. swift简单总结(七)—— 数据类型
8. swift简单总结(八)—— 别名、布尔值与元组
9. swift简单总结(九)—— 可选值和断言
10. swift简单总结(十)—— 运算符
11. swift简单总结(十一)—— 字符串和字符
12. swift简单总结(十二)—— 集合类型之数组
13. swift简单总结(十三)—— 集合类型之字典
14. swift简单总结(十四)—— 控制流
15. swift简单总结(十五)—— 控制转移语句
16. swift简单总结(十六)—— 函数
17. swift简单总结(十七)—— 闭包(Closures)
18. swift简单总结(十八)—— 枚举
19. swift简单总结(十九)—— 类和结构体
20. swift简单总结(二十)—— 属性
21. swift简单总结(二十一)—— 方法
22. swift简单总结(二十二)—— 下标脚本
23. swift简单总结(二十三)—— 继承
24. swift简单总结(二十四)—— 构造过程
25. swift简单总结(二十五)—— 构造过程
26. swift简单总结(二十六)—— 析构过程
27. swift简单总结(二十七)—— 自动引用计数
28. swift简单总结(二十八)—— 可选链
29. swift简单总结(二十九)—— 类型转换
30.swift简单总结(三十)—— 嵌套类型
31.swift简单总结(三十一)—— 扩展
32.swift简单总结(三十二)—— 协议
33.swift简单总结(三十三)—— 泛型

访问控制

访问控制可以限定你在源文件或模块中访问代码的级别,也就是说可以控制哪些代码你可以访问,哪些代码你不可以访问,这个特性可以让我们隐藏功能实现的一些细节,并且可以明确的指定我们提供给其他人的接口中哪些部分是他们可以使用的,哪些是他们看不到的。

下面将从以下几点进行说明

  • 模块和源文件
  • 访问级别
    • 访问级别的使用原则
    • 默认访问级别
    • 单目标应用程序的访问级别
    • Framework的访问级别
  • 访问控制语法
  • 自定义类型
    • 元组类型
    • 函数类型
    • 枚举类型
    • 原始值和关联值
    • 嵌套类型
  • 子类
  • 常量、变量、属性和下标
    • Getter&&Setter
  • 初始化
    • 默认初始化方法
    • 结构体的默认成员初始化方法
  • 协议
    • 协议继承
    • 协议一致性
  • 扩展
    • 协议的扩展
  • 泛型
  • 类型别名

模块和源文件

swift中的访问控制模型基于模块和源文件这两个概念。这里,模块指的是Frameworkapp bundle,在swift中使用import关键字引入自己的工程。

源文件指的是swift中的swift File,就是编写swift代码的文件,它属于一个模块,通常一个源文件包含一个类,在类中又包含函数,属性等类型。


访问级别

swift提供了三种不同的访问级别,这些访问级别相当于源文件中定义的实体,同时也相对于这些源文件所属的模块。

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

public是最高访问级别,private是最低访问级别。

1. 访问级别的使用原则

原则:访问级别统一性

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

2. 默认访问级别

代码中的所有实体,如果你不明确的定义其访问级别,那么它们的默认为Internal级别,在大多数情况下,我们不需要明确的设置实体的访问级别,因为也大多数时候在开发一个App Bundle

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

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

4. Framework的访问级别

当你开发Framework时,你就需要把一些实体定义为Public级别,以便其他人导入即可正常使用,这些被定义为Public的实体,就是这个Framework的API。这里要注意:Framework的内部显示细节依然可以使用默认的Internal级别,或者也可以定义为Private级别,只有你想将它作为API的实体,才将其定义为Public级别。


访问控制语法

通过修饰符publicinternalprivate来声明实体的访问级别。

public class SomePublicClass{

}

internal class SomeInternalClass{

}

private class SomePrivateClass{

}

上面就是几种类的访问级别的声明方式。

除非有特殊的说明,否则实体都使用默认的访问级别internal

//隐式访问级别 internal
class SomeInternalClass{
    //隐式访问级别internal
    var someInternalConstant = 0
}

自定义类型

如果你想为一个自定义类型指定一个明确的访问级别,你要明确一点,你要确保新类型的访问级别和它实际的作用域相匹配。

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

注意:一个public类的所有成员的访问级别默认为internal级别,而不是public级别,如果你想将某个成员申明为public级别,那么你必须使用修饰符明确的申明该成员。

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

class SomeInternalClass{                  //隐式访问级别 internal
    var someInternalConstant = 0          //隐式访问级别internal
    private func somePrivateMethod(){     //显示的private类成员
    }
}

private class SomePrivateClass{         //显式的private类
    var somePrivateProperty = 0         //隐式的private类成员
    func somePrivateMethod(){           //隐式的private类成员
    
    }
}

1. 元组类型

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

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

2. 函数类型

函数的访问级别需要根据该函数的参数类型访问级别、返回类型访问级别得出。

下面看个简单例子。

func someFunction() -> (SomeInternalClass, SomePrivateClass){
    //function goes here
}

由于返回类型是元组,一个元素是internal,另外一个元素就是private,那么返回值类型是private,但是这里有个问题,编译不过去,因为函数返回值级别是private,那么你必须使用private修饰符,明确的申请该函数。

private func someFunction() -> (SomeInternalClass, SomePrivateClass){
    //function goes here
}

3. 枚举类型

枚举中成员的访问级别继承自该枚举,你不能为枚举中的成员指定访问级别。看下面个简单例子。

public enum CompassPoint{
    case North
    case South
    case East
    case West
}

枚举CompassPoint被明确的声明为public,那么North等四个成员访问基本也是public

4. 原始值和关联值

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

5. 嵌套类型

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

子类

子类的访问级别不能高于父类的访问级别。

下面看一个简单例子。

public class A{
    func someMethod(){
    
    }
}

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

这里,类A的访问级别是public,它包含一个函数someMethod,访问级别是internal,类B继承自类A,并且访问级别申明为internal,但是在类B中重写了类A中访问级别为internal的方法someMethod,并重写声明为internal级别,通过这种方式,我们就可以访问到某类中private级别的类成员,并且可重新声明其访问级别。


常量、变量、属性、下标

常量、变量、属性不能拥有比它们的类型更高的访问级别,比如,你定义一个public级别的属性,但是它的类型是private级别的,这是编译器不允许的。

1. Getter && Setter

常量、变量、属性和下标索引的settergetter的访问级别继承自他们所属成员的访问级别。setter的访问级别可以低于对应getter的访问级别,这样就可以控制变量、属性或下标索引的读写权限。

使用private(set)private(get)可以改变swift隐式创建的setter的访问级别。

下面看一个简单例子。

class JJPracticeVC: UIViewController {

    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        var stringToEdit = TrackedString()
        stringToEdit.value = "1"
        stringToEdit.value = "2"
        print("number is \(stringToEdit.numberOfEdits)")
    }
}

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

下面看一下输出结果

number is 2

这里,numberOfEdits属性的getter依然是默认的访问级别internalsetter的访问级别是private,这表示该属性只有在当前的源文件中是可读可写的,在当前源文件所属模块中它只是一个可读的属性。


初始化

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

如同函数或方法参数,初始化方法参数访问级别也不能低于初始化方法的访问级别。

1. 默认初始化方法

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

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

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

如果结构体的任意存储属性的访问级别为private,那么它的默认成员初始化方法的访问级别就是private,尽管如此,结构体的初始化方法的访问级别依然是internal。如果你想要在其他模块中使用该结构体的默认成员初始化方法,那么你需要提供一个访问级别为public的默认成员初始化方法。


协议

如果你想为一个协议明确的申明访问级别,那么你就要确保该协议只在你申明的访问级别作用域中使用。协议中的每一个必要实现的函数都具有该协议相同的访问级别,这样才能确保该协议的使用者可以实现它所提供的函数。

如果你定义了一个public访问级别的协议,那么实现该协议提供的必要函数也会是public的访问级别,这一点不用于其他类型。

1. 协议继承

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

2. 协议一致性

类可以采用比自身访问级别低的协议。采用了协议的类的访问级别遵循它本身和采用协议中最低的访问级别,也就是说如果一个类是public级别,采用的协议是internal级别,那么采用这个协议后,该类的访问级别也是internal

如果你采用了协议,那么实现了协议必须的方法后,该方法的访问级别遵循协议的访问级别,比如说,一个public级别的类,采用了internal级别的协议,那么该类实现协议的方法至少也得是internal


扩展

扩展成员应该具有和原始类成员一致的访问级别。你也可以明确申明扩展的访问级别给该扩展内所有成员指定一个新的默认访问级别,这个默认的访问级别仍然可以被单独成员所指定的访问级别所覆盖。

1. 协议的扩展

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


泛型

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


类型别名

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

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

后记

未完,待续~~~

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

推荐阅读更多精彩内容