美文网首页swift
《Swift从入门到精通》(二十三):访问控制

《Swift从入门到精通》(二十三):访问控制

作者: 萧1帅 | 来源:发表于2021-10-20 09:05 被阅读0次

    访问控制(Access Control)(学习笔记)

    环境Xcode 11.0 beta4 swift 5.1
    欢迎留言 pen me

    • 前言

      访问控制是限制从其它文件和模块访问部分模块的代码,你可以为个别类型(class\struct\enum)或属于这些的属性、方法、初始化器等添加访问权限,Swift提供了默认的访问权限,如果编写单一应用程序时,可能根本用不到要显示指定访问控制级别
    • 模块和源文件

      • Swift的访问控制是建立在模块和源文件的基础上。
      • 模块是代码分发的单个单元,一个framework或application构建或发布可以作为一个单元。给其它模块导入,用 import 关键字
      • 源文件是定义在模块中的单个文件(.swfit文件),通常一个源文件定义一个类型,但也可以定义多个
    • 访问级别

      • Swift定义了五种访问级别(限制级别从松到严),都是相对模块和源文件来说

      • openpublic可以访问当前定义模块任意源文件,也可访问通过import导入后的文件,不同的是open仅适用于类和类的成员,与public的区别在于可以被外面的模块继承

      • internal 可以访问当前定义模块内的任意源文件

      • fileprivate 严格限制访问当前文件

      • private 限制在一个封闭的声明中使用以及在同一个文件的扩展中使用

      • 访问级别设计指导原则:大的原则是权限大的不能定义在权限小中定义,如一个公共变量内部不使用权限小的类型,或一个函数比其参数或返回值拥有更高的访问级别

      • 默认访问级别:internal(除了下面提到的几种特定的情况),多数情况下在代码中不用显示指定访问级别

      • 作为独立目标应用程序的访问权限 internal权限在模块内部已足够使用,作为Framework的访问级别一般提供给外界使用,一般是 open public, 单元测试模块默认是当前模块可以任意访问,只有标有open public才能被其它模块使用

    • 基本语法

      • 用关键字 open public internal fileprivate private

        public class SomePublicClass {}
        internal class SomeInternalClass {}
        fileprivate class SomeFilePrivateClass {}
        private class SomePrivateClass {}
        // 
        public var somePublicVariable = 0
        internal let someInternalConstant = 0
        fileprivate func someFilePrivateFunction() {}
        private func somePrivateFunction() {}
        // 默认的internal
        class SomeInternalClass {}              
        let someInternalConstant = 0 
        
        
      • 自定义类型,内部的权限 <= 外部的权限

        public class SomePublicClass {                  // explicitly public class
            public var somePublicProperty = 0            // explicitly public class member
            var someInternalProperty = 0                 // implicitly internal class member
            fileprivate func someFilePrivateMethod() {}  // explicitly file-private class member
            private func somePrivateMethod() {}          // explicitly private class member
        }
        //
        class SomeInternalClass {                       // implicitly internal class
            var someInternalProperty = 0                 // implicitly internal class member
            fileprivate func someFilePrivateMethod() {}  // explicitly file-private class member
            private func somePrivateMethod() {}          // explicitly private class member
        }
        //
        fileprivate class SomeFilePrivateClass {        // explicitly file-private class
            func someFilePrivateMethod() {}              // implicitly file-private class member
            private func somePrivateMethod() {}          // explicitly private class member
        }
        //
        private class SomePrivateClass {                // explicitly private class
            func somePrivateMethod() {}                  // implicitly private class member
        }
        
        
      • 元组类型权限, 如 一个元组(internal, private),那它的权限是private

      • 函数类型权限

        func someFunction() -> (SomeInternalClass, SomePrivateClass) {
            // do something
        }
        // 上面函数没有使用权限修饰,你可能期望函数是 `internal`
        // 但你错了,编译都不会过,因为你返回元组的一个权限是 private
        // 如下才是正确的
        private func someFunction() -> (SomeInternalClass, SomePrivateClass) {
            // do something
        }
        
        
      • 枚举类型:每个case自动匹配枚举类型的权限,不能单独指定某个case的权限,如下每个case都是public

        public enum CompassPoint {
            case north
            case south
            case east
            case west
        }
        
        
        • 对于枚举的关联值和原始值访问级别 >= 当前枚举类型的访问级别,例如:原始值类型用private修饰,枚举类型用internal修饰,这样是不行的
        • 嵌套类型的权限与外层相同,如果外层是public,嵌套类型要显示申明为public才是public类型,否则是internal
      • 子类化,尝试如下两个类在同一个文件和同一模块不同文件中的情况

        public class A {
            fileprivate func someMethod() {}
        }
        internal class B: A {
            override internal func someMethod() {}
        }
        // 同一文件中是可以的
        // 同一模块不同文件中是不可以的
        public class A {
            fileprivate func someMethod() {}
        }
        internal class B: A {
            override internal func someMethod() {
                super.someMethod()
            }
        }
        
        
    • 常量、变量、属性、下标访问权限

      • 它们的权限不会高于它们的类型权限,如果你的类型是private,那么它们在声明的时候必须是private

      • 它们的Getter\Setter与它们有相同的权限,有时你可以给Setter设置一个更低的权限,在 var 前用 fileprivate(set)\private(set)\internal(set),如下无示例

        struct TrackedString {
            private(set) var numberOfEdits = 0 // **
            var value: String = "" {           // **
                didSet {
                    numberOfEdits += 1
                }
            }
        }
        var stringToEdit = TrackedString()
        stringToEdit.value = "This string will be tracked."
        stringToEdit.value += " This edit will increment numberOfEdits."
        stringToEdit.value += " So will this one."
        print("The number of edits is \(stringToEdit.numberOfEdits)")
        // Prints "The number of edits is 3"
        // 虽然setter是private,但getter还是默认的internal
        // 当然也可以在上面 ** 标记的那两行显示的用public权限修饰词来修饰
        
        
    • 初始化器权限

      • 除了指定初始化器的权限必须与定义的类型一致,其它的初始化器的权限均可小于等于类型的权限
      • 在没有自定义初始化器时,Swift有默认初始化器,与类型的权限一样,如果类型是public则取默认的internal,要同样是public要显示声明
      • 对于结构体,如果没有自定义初始化器,系统会默认生成一个全成员参数的初始化器,此时的权限要取决于成员变量的权限
    • 协议权限

      • 如果想显示的分配协议的访问类型,在协议定义的时候进行
      • 协议中定义的每个方法自动与协议的权限匹配,确保所有遵守该协议的任何类型都能访问都是一样的
      • 如果是继承一个已存在的协议,权限小于等于被继承的协议
      • 协议的一致性,如果有一个类是public但协议是internal,此时类遵守该协议,此时类实现协议的所有方法的权限相至少为internal
    • 扩展

      • 如果给一个public\internal类扩展时,添加的任何成员变量权限是internal,如果是fileprivate\private则是成员权限为fileprivate\private
      • 同一个文件添加的扩展中添加私有成员,此时私有的成员可以在原始定义、扩展、其它扩展中相互访问
    • 泛型

      • 与元组很类似,泛型函数或泛型类型都与给定的类型参数权限最低的相同
    • 类型别名

      • 出于访问控制的目的,类型别名被视为不同的类型,其访问的权限要小于等于其别名的类型的权限

    相关文章

      网友评论

        本文标题:《Swift从入门到精通》(二十三):访问控制

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