美文网首页iOS进阶IOS开发经验iOSer 的自我修养
Swift 3必看:新的访问控制fileprivate和open

Swift 3必看:新的访问控制fileprivate和open

作者: 没故事的卓同学 | 来源:发表于2016-09-09 00:26 被阅读36919次

    在swift 3中新增加了两种访问控制权限<code> fileprivate </code>和<code> open </code>。下面将对这两种新增访问控制做详细介绍。

    fileprivate

    在原有的swift中的<code> private </code>其实并不是真正的私有,如果一个变量定义为private,在同一个文件中的其他类依然是可以访问到的。这个场景在使用extension的时候很明显。

    class User {
        private var name = "private"
    }
    
    extension User{
        var accessPrivate: String {
            return name
        }
    }
    

    这样带来了两个问题:

    • 当我们标记为private时,意为真的私有还是文件内可共享呢?
    • 当我们如果意图为真正的私有时,必须保证这个类或者结构体在一个单独的文件里。否则可能同文件里其他的代码访问到。

    由此,在swift 3中,新增加了一个<code> fileprivate </code>来显式的表明,这个元素的访问权限为文件内私有。过去的private对应现在的fileprivate。现在的private则是真正的私有,离开了这个类或者结构体的作用域外面就无法访问。

    open

    open则是弥补public语义上的不足。
    现在的open有两层含义:

    • 这个元素可以在其他作用域被访问
    • 这个元素可以在其他作用域被继承或者override

    继承是一件危险的事情。尤其对于一个framework或者module的设计者而言。在自身的module内,类或者属性对于作者而言是清晰的,能否被继承或者override都是可控的。但是对于使用它的人,作者有时会希望传达出这个类或者属性不应该被继承或者修改。这个对应的就是<code> final </code>。

    <code> final </code>的问题在于在标记之后,在任何地方都不能override。而对于lib的设计者而言,希望得到的是在module内可以被override,在被import到其他地方后其他用户使用的时候不能被override。

    这就是<code> open </code>产生的初衷。通过open和public标记区别一个元素在其他module中是只能被访问还是可以被override。

    下面是例子:

    /// ModuleA:
    
    // 这个类在ModuleA的范围外是不能被继承的,只能被访问
    public class NonSubclassableParentClass {
    
        public func foo() {}
    
        // 这是错误的写法,因为class已经不能被继承,
        // 所以他的方法的访问权限不能大于类的访问权限
        open func bar() {}
    
        // final的含义保持不变
        public final func baz() {}
    }
    
    // 在ModuleA的范围外可以被继承
    open class SubclassableParentClass {
        // 这个属性在ModuleA的范围外不能被override
        public var size : Int
    
        // 这个方法在ModuleA的范围外不能被override
        public func foo() {}
    
        // 这个方法在任何地方都可以被override
        open func bar() {}
    
        ///final的含义保持不变
        public final func baz() {}
    }
    
    /// final的含义保持不变
    public final class FinalClass { }
    
    /// ModuleB:
    
    import ModuleA
    
    // 这个写法是错误的,编译会失败
    // 因为NonSubclassableParentClass类访问权限标记的是public,只能被访问不能被继承
    class SubclassA : NonSubclassableParentClass { }
    
    // 这样写法可以通过,因为SubclassableParentClass访问权限为 `open`.
    class SubclassB : SubclassableParentClass {
       
        // 这样写也会编译失败
        // 因为这个方法在SubclassableParentClass 中的权限为public,不是`open'.
        override func foo() { }
    
        // 这个方法因为在SubclassableParentClass中标记为open,所以可以这样写
        // 这里不需要再声明为open,因为这个类是internal的
        override func bar() { }
    }
    
    open class SubclassC : SubclassableParentClass {
        // 这种写法会编译失败,因为这个类已经标记为open
        // 这个方法override是一个open的方法,则也需要表明访问权限
        override func bar() { } 
    }
    
    open class SubclassD : SubclassableParentClass {
        // 正确的写法,方法也需要标记为open
        open override func bar() { }    
    }
    
    open class SubclassE : SubclassableParentClass {
        // 也可以显式的指出这个方法不能在被override
        public final override func bar() { }    
    }
    

    总结

    现在的访问权限则依次为:open,public,internal,fileprivate,private。
    有的人会觉得访问权限选择的增加加大了语言的复杂度。但是如果我们思考swift语言的设计目标之一就是一门安全的语言(“Designed for Safety”)就能理解这次的改动。更加明确清晰的访问权限控制可以使程序员表达出更准确的意图,当然也迫使在编码时思考的更加深入。

    欢迎关注我的微博:@没故事的卓同学
    相关链接:
    SE0025-Scoped Access Level
    SE0117-Allow distinguishing between public access and public overridability

    相关文章

      网友评论

      • afdjsajfdsl:swift4.1中 'private' 等价于 ‘fileprivate’; swift3.3 中确实如上面所说 ‘private‘ 更严格。
      • 不不不不同学:点下第6000个赞的同时,想请教下。

        Markdown怎么换行呢?我试过br的两种形式,以及空格+换行,均不行。
      • 571ef0ae8ccf:谢谢 理解了
      • 星火燎原:我只回复好贴
      • Pishum:楼主你好,Swift3.1的public类是可以被override和继承的
        目染江夏:那现在 public 和 open 到底区别是什么呀 感觉一样呀
        没故事的卓同学:@Pishum 嗯。过阵子我改一下
        Pishum:swift3.0.2
      • 妹子爱编程:小哥哥棒棒哒
      • 2fb4e185e098:swift3.0 中同一文件 extension 访问不到 private 修饰的方法,变量
      • d976e6bc9ea9:坑啊,还这么多人点赞,明显open 和 public就自相矛盾。
      • 化城:留言是一种态度:smiley:
      • ethan_cun:public的两层含义第二点和例子相反:sweat:
      • 5ec1da87f063:我试了怎么和你说的private 和fileprivate是反的.在extension里面只有fileprivate可以访问到,frivate反而不行.
        llllllllIllllIl:@llllllllllll511 这个傻屌写的鸡巴玩样,你看不懂正常
        llllllllIllllIl:Swift 4再试,Swift2试下。
      • AirZilong:不错
      • d38820c22442:我刚在Xcode8.2.1上父类在声明的时候用public修饰,也能被继承,还有父类中的方法被public修饰后,子类中仍然可以被override重写。作者你试试
        没故事的卓同学:@iOS杨少 你换个framework,internal里当然可以了。
      • Camoufleur:受教了
      • JsJavaCoder:open public internal fileprivate private
      • JsJavaCoder:敲敲代码印象会深刻一点open,public,internal,fileprivate,private
        omni_Hsin:me too, open public internal fileprivate private
      • VinZZZZ:还有最后总结, ”访问权限则依次为open,public,internal,fileprivate,private。“, 不是fileprivate权限最低么?
        VinZZZZ:@上天入地无所不能无所不晓 嗯,是这样的
        上天入地无所不能无所不晓:@Vin周 fileprivate是文件私有,一个文件是可以有多个类的,标记为fileprivate的常理在多个类里面都可以用,但如果标记为private,在不同类是不能访问的。
        VinZZZZ:看了参考链接,原来Swift3对private的含义进行了调整,其在Swift2的scope被fileprivate取代;public: symbol visible outside the current module
        internal: symbol visible within the current module
        fileprivate: symbol visible within the current file
        private: symbol visible within the current declaration
      • VinZZZZ:现在的pubic有两层含义:..., 这个元素可以在其他作用域被继承或者override . 看代码是不能被继承或override?
      • 某个胖子:经过测试,swift3.0下private修饰的变量不可在本文件的其他扩展或者类中使用。
        smkoc:我也是测试了, 只有filePrivate 可以在本文件的其他扩展或者类中使用
      • Hengry:mark一下
      • 荔枝lizhi_iOS程序猿:楼主写的很好,很实用,
      • 码农冰冰:正在学习中,我现在用private 同一类中一直访问不到,改成file private可以了
        残翅天使:没反,现在的fileprivate就是过去的private,是可以在同一文件中访问到的。
        而现在的private和java的很像,只能本类访问。。

        不过所说的同一类访问不到应该指的同一个文件吧。。
        同一类访问不到是什么鬼,局部变量么?
        三分慢先森:@Duangser 事实就是那样的 没反
        Venhoe:你搞反了吧
      • 会疼的白痴:你确定private可以在扩展类里面用?
        梁同桌:@会疼的白痴 在2.2 版本也是不可用的
      • 米苏芊:棒。对于转Swift3.0有很大帮助
      • 89e5d924711e:写的很好,感谢楼主
      • 亲密数:才知道
      • lucasdada:加油,互相添油
      • 740b3fd6f09f:mark 一下
      • 判若两人丶:我也去试试
      • Zoros:明天试一下:smile:

      本文标题:Swift 3必看:新的访问控制fileprivate和open

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