美文网首页
Swift进阶(十六)访问控制

Swift进阶(十六)访问控制

作者: Jax_YD | 来源:发表于2021-01-27 17:27 被阅读0次

    访问控制(Access Control)

    • 在访问权限控制这块,Swift提供了5个不同的访问级别(以下是从高到低排列,实体指被访问级别修饰的内容):
      open:允许在定义实体的模块、其他模块中访问,允许其他模块进行继承、重写(open只能用在类、类成员上)
      public:允许在定义实体的模块、其他模块中访问,不允许其他模块进行继承、重写
      internal:只允许在定义实体的模块中访问,不允许在其他模块中访问
      fileprivate:只允许在定义实体的源文件中访问
      private:只允许在定义实体的封闭声明中访问

    • 绝大部分实体默认都是internal级别


    访问级别的使用准则

    • 一个实体不可以被更低访问级别的实体定义,如下:
      □ 变量\常量类型 \color{orange}{≥} 变量\常量
      □ 参数类型、返回值类型 \color{orange}{≥} 函数
      □ 父类 \color{orange}{≥} 子类
      □ 父协议 \color{orange}{≥} 子协议
      □ 原类型 \color{orange}{≥} typealias
      □ 原始值类型、关联值类型 \color{orange}{≥} 枚举类型
      □ 定义类型A时用到的其他类型 \color{orange}{≥} 类型A
      □ ......

    下面我们来解释一下上面面的规则:

    • 变量\常量类型 \color{orange}{≥} 变量\常量

      image.png
      上面我们讲过struct Point {}的默认级别是internal,同样p1、p2、p_1、p_2的默认级别也是internal,然而struct Point_1 {}的级别是private小于internal。那么如果说外界访问p_1、p_2时,又没有权限访问Point_1,这就是矛盾的,所以会报错。
    • 参数类型、返回值类型 \color{orange}{≥} 函数

      image.png
    • 父类 \color{orange}{≥} 子类

      image.png
      能访问到子类必然也要能访问到父类,所以父类的级别要大于等于子类
    • 父协议 \color{orange}{≥} 子协议

      image.png
    • 原类型 \color{orange}{≥} typealias

      image.png
    • 原始值类型、关联值类型 \color{orange}{≥} 枚举类型

      image.png
    • 定义类型A时用到的其他类型 \color{orange}{≥} 类型A

      image.png

    元组类型

    • 元组类型的访问级别,跟所有成员类型中最底的级别保持一致
    internal class Dog {}
    fileprivate class Animal {}
    
    fileprivate var data: (Dog, Animal) // (Dog, Animal)的访问级别是fileprivate
    

    泛型类型

    • 泛型类型的访问级别是 \color{orange}{类型的访问级别} 以及 \color{orange}{所有泛型类型参数的访问级别} 中最底的那个
    internal class Dog {}
    fileprivate class Cat {}
    public class Animal<T1, T2> {}
    
    fileprivate var animal = Animal<Dog, Cat>() // Animal<Dog, Cat>()的访问级别是fileprivate
    

    成员、嵌套类型

    • 类型的访问级别会影响成员(属性、方法、初始化器、下标)、嵌套类型的访问级别
      □ 一般情况下,类型为privatefileprivate,那么成员\嵌套类型默认也是privatefileprivate
      □ 一般情况下,类型为internalpublic,那么成员\嵌套类型默认是internal
    private class Person {
        var name: String = "" // private
        var age: Int = 0 // private
        
        enum city { // private
            case beijing
            case nanjing
        }
    }
    
    public class Animal {
        public var type = 0 // public
        var name = "" // internal
        fileprivate func fun1() {} // fileprivate
        private func fun2() {} // private
    }
    

    这里大家要注意一个\color{orange}{作用域}的问题,比如上面Person的嵌套类型city的级别是private,那么city内部成员的级别也就是private;在这种情况下Person能否访问city的内部成员呢?
    答案是:可以的
    因为city内部成员没有单独显示声明级别,那么其所对应的级别跟city保持一致也是private,其访问级别作用域也保持一致,也是Person。所以可以访问。

    同样的,在全局作用域中fileprivateprivate的修饰没有什么区别,作用域都是当前文件。如下代码:

    image.png

    成员的重写

    • 子类重写成员的访问级别必须 \color{orange}{≥} 子类的访问级别,或者 \color{orange}{≥} 父类被重写成员的访问级别
    • 父类的成员不能被成员作用域外定义的子类重写

    正常情况下,我们是这样写的:

    class Person {
        var age: Int = 0
    }
    
    class Student: Person {
        override var age: Int {
            set {}
            get {13}
        }
    }
    

    第一种情况:降低重写后的age访问级别

    image.png
    第二种情况:降低重写前的age访问级别
    image.png
    此时age的作用域只存在于Person内部,所以如果我们想在子类中重写age,我们除了可以增加age的权限之外,还可以把子类写在Person内部
    image.png

    getter、setter

    • gettersetter默认自动接收它们所属环境的访问级别
    • 可以给setter单独设置一个比getter更低的访问级别,用以限制写的权限
      注意:getter的权限不能比setter
    // num可以在其他实体中被访问,但是只能在当前文件中被修改
    fileprivate(set) public var num = 10
    
    class Person {
        private(set) var name = "Aaron"
        fileprivate(set) public var age: Int {
            set {}
            get { 10 }
        }
    }
    

    初始化器

    • 如果一个public类想在另一个模块调用编译生成的默认无参初始化器,必须\color{orange}{显示提供} public无参初始化器
      □ 因为public类的默认初始化器是internal级别(在写一些提供给别人用的库的时候会用到)
    • required初始化器 \color{orange}{≥} 它的默认访问级别
    • 如果结构体有private\fileprivate的存储实例属性,那么它的\color{orange}{成员初始化器}也是private\fileprivate
      □ 否则默认是internal
      image.png

    枚举类型的case

    • 不能给enum的每个case单独设置访问级别
    • 每个case自动接收enum的访问级别
      注意:public enum定义的case也是public,这一点与上面的结构体、类有一定的区别
      image.png

    协议

    • 协议中\color{orange}{定义的要求},自动接收协议的访问级别,不能单独设置访问级别
      public协议定义的要求也是public,这一点与上面的结构体、类有一定的区别
      image.png
    • 协议实现的访问级别必须 \color{orange}{≥} 类型的访问级别,或者 \color{orange}{≥} 协议的访问级别。也就是说要 $\color{orange}{≥} 两者中最小的那个。
      image.png
      大家注意,下面的代码也是不行的,因为public修饰类的时候,类里面的成员默认是internal
      image.png

    扩展

    • 如果有显示设置扩展的访问级别,扩展添加的成员自动接收扩展的访问级别

    • 如果没有显示设置扩展的访问级别,扩展添加的成员默认访问级别,跟直接在类型中定义的成员一样

    • 可以单独给扩展中添加的成员设置访问级别

    • 不能给遵守协议的扩展显示设置扩展的访问级别


      image.png
    • 在同一个文件中的扩展,可以写成类似多个部分的类型声明
      □ 在原本的声明中,声明一个私有成员,可以在同一个文件的扩展中访问它。
      □ 在扩展中声明一个私有成员,也可以在同一个文件的其他扩展中,或者原本的声明中访问它。

      image.png

    相关文章

      网友评论

          本文标题:Swift进阶(十六)访问控制

          本文链接:https://www.haomeiwen.com/subject/jmfnzktx.html