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的类型。

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

后记

未完,待续~~~

swift简单总结(三十四)—— 访问控制_第1张图片
长城

你可能感兴趣的:(swift简单总结(三十四)—— 访问控制)