首页 文章

Swift有访问修饰符吗?

提问于
浏览
262

在Objective-C实例中,数据可以是 publicprotectedprivate . 例如:

@interface Foo : NSObject
{
  @public
    int x;
  @protected:
    int y;
  @private:
    int z;
  }
-(int) apple;
-(int) pear;
-(int) banana;
@end

我没有在Swift参考中找到任何访问修饰符 . 是否可以限制Swift中数据的可见性?

17 回答

  • 1

    As of Swift 3.0.1, there are 4 levels of access,从最高(最少限制)到最低(最具限制性)描述如下 .


    1.开放和公开

    允许在定义模块(目标)之外使用实体 . 在指定框架的公共接口时,通常使用 openpublic 访问 .

    但是, open access applies only to classes and class members ,它与 public access的区别如下:

    • public 类和类成员只能在定义模块(目标)中进行子类化和重写 .

    • open 类和类成员可以在定义模块(目标)内部和外部进行子类化和重写 .

    // First.framework – A.swift
    
    open class A {}
    
    // First.framework – B.swift
    
    public class B: A {} // ok
    
    // Second.framework – C.swift
    
    import First
    
    internal class C: A {} // ok
    
    // Second.framework – D.swift
    
    import First
    
    internal class D: B {} // error: B cannot be subclassed
    

    2.内部

    允许在定义模块(目标)中使用实体 . 在定义应用程序或框架的内部结构时,通常使用 internal 访问 .

    // First.framework – A.swift
    
    internal struct A {}
    
    // First.framework – B.swift
    
    A() // ok
    
    // Second.framework – C.swift
    
    import First
    
    A() // error: A is unavailable
    

    3. fileprivate

    将实体的使用限制在其定义的源文件中 . 当在整个文件中使用这些详细信息时,通常使用 fileprivate 访问来隐藏特定功能的实现细节 .

    // First.framework – A.swift
    
    internal struct A {
    
        fileprivate static let x: Int
    
    }
    
    A.x // ok
    
    // First.framework – B.swift
    
    A.x // error: x is not available
    

    4.私人

    限制实体在其附件声明中的使用 . 当这些详细信息仅在单个声明中使用时,通常使用 private 访问来隐藏特定功能的实现细节 .

    // First.framework – A.swift
    
    internal struct A {
    
        private static let x: Int
    
        internal static func doSomethingWithX() {
            x // ok
        }
    
    }
    
    A.x // error: x is unavailable
    
  • 395

    language grammar没有关键字'public','private'或'protected' . 这表明一切都是公开的 . 当然,可能有一些替代方法来指定访问修饰符而没有那些关键字,但我在语言参考中找不到它 .

  • 3

    斯威夫特4

    正如Swift Documentation - Access Control中所述, Swift 4 有5个访问控制:

    • openpublic :可以从导入定义模块的模块's entities and any module'实体访问 .

    • internal :只能从其模块的实体访问 . 这是默认的访问级别 .

    • fileprivateprivate :只能在您定义它们的有限范围内限制访问 .


    开放和公共有什么区别?

    open 与以前版本的Swift中的public相同,它们允许来自其他模块的类使用和继承它们,即:它们可以从其他模块子类化 . 此外,它们允许来自其他模块的成员使用和覆盖它们 . 他们的模块也采用相同的逻辑 .

    public 允许来自其他模块的类使用它们,但不允许继承它们,即:它们不能从其他模块中继承 . 此外,它们允许来自其他模块的成员使用它们,但不要覆盖它们 . 对于他们的模块,它们具有相同的开放逻辑(它们允许类使用和继承它们;它们允许成员使用和覆盖它们) .

    fileprivate和private有什么区别?

    fileprivate 可以从他们的整个文件中访问 .

    private 只能从他们的单一声明和同一文件中的声明的扩展名访问;例如:

    // Declaring "A" class that has the two types of "private" and "fileprivate":
    class A {
        private var aPrivate: String?
        fileprivate var aFileprivate: String?
    
        func accessMySelf() {
            // this works fine
            self.aPrivate = ""
            self.aFileprivate = ""
        }
    }
    
    // Declaring "B" for checking the abiltiy of accessing "A" class:
    class B {
        func accessA() {
            // create an instance of "A" class
            let aObject = A()
    
            // Error! this is NOT accessable...
            aObject.aPrivate = "I CANNOT set a value for it!"
    
            // this works fine
            aObject.aFileprivate = "I CAN set a value for it!"
        }
    }
    

    Swift 3和Swift 4访问控制有什么区别?

    正如SE-0169 proposal中所提到的,Swift 4中唯一的改进是私有访问控制范围已扩展为可以从同一文件中的声明扩展访问;例如:

    struct MyStruct {
        private let myMessage = "Hello World"
    }
    
    extension MyStruct {
        func printMyMessage() {
            print(myMessage)
            // In Swift 3, you will get a compile time error:
            // error: 'myMessage' is inaccessible due to 'private' protection level
    
            // In Swift 4 it should works fine!
        }
    }
    

    因此,无需将 myMessage 声明为fileprivate即可在整个文件中访问 .

    补充说明:如果您遇到与未使用迁移的旧Swift 3项目编译Swift 4相关的问题,您可以查看此问答 .

  • 3

    当谈到在Swift或ObjC(或ruby或java或......)中创建一个"private method"时,这些方法并不是真正的私有 . 它们周围没有实际的访问控制 . 任何提供甚至一点内省的语言都可以让开发人员从课堂外获得这些 Value ,如果他们真的想要的话 .

    所以我们在这里真正谈到的是一种定义面向公众的界面的方法,该界面仅提供我们想要的功能,以及"hides"我们认为的其余部分"private" .

    用于声明接口的Swift机制是 protocol ,它可以用于此目的 .

    protocol MyClass {
      var publicProperty:Int {get set}
      func publicMethod(foo:String)->String
    }
    
    class MyClassImplementation : MyClass {
      var publicProperty:Int = 5
      var privateProperty:Int = 8
    
      func publicMethod(foo:String)->String{
        return privateMethod(foo)
      }
    
      func privateMethod(foo:String)->String{
        return "Hello \(foo)"
      }
    }
    

    请记住,协议是一流的类型,可以在任何类型的地方使用 . 而且,当以这种方式使用时,它们只暴露自己的接口,而不是那些接口实施类型 .

    因此,只要在参数类型等中使用 MyClass 而不是 MyClassImplementation ,它应该只是起作用:

    func breakingAndEntering(foo:MyClass)->String{
      return foo.privateMethod()
      //ERROR: 'MyClass' does not have a member named 'privateMethod'
    }
    

    有一些直接分配的情况,你必须明确与类型,而不是依靠Swift推断它,但这似乎不是一个交易破坏者:

    var myClass:MyClass = MyClassImplementation()
    

    使用协议这种方式是语义的,相当简洁,我的眼睛看起来很像我们在ObjC中用于此目的的类扩展 .

  • 0

    据我所知,没有关键字'public','private'或'protected' . 这表明一切都是公开的 .

    然而,Apple可能期望人们使用“protocols”(世界其他地方称为接口)和factory design pattern来隐藏实现类型的细节 .

    无论如何,这通常是一种很好的设计模式;因为它允许您更改 implementation 类层次结构,同时保持 logical 类型系统相同 .

  • 2

    使用协议,闭包和嵌套/内部类的组合,可以使用模块模式的某些内容来隐藏Swift中的信息 . 它不是超级干净或阅读不错但它确实有效 .

    例:

    protocol HuhThing {
      var huh: Int { get set }
    }
    
    func HuhMaker() -> HuhThing {
       class InnerHuh: HuhThing {
        var innerVal: Int = 0
        var huh: Int {
          get {
            return mysteriousMath(innerVal)
          }
    
          set {
           innerVal = newValue / 2
          }
        }
    
        func mysteriousMath(number: Int) -> Int {
          return number * 3 + 2
        }
      }
    
      return InnerHuh()
    }
    
    HuhMaker()
    var h = HuhMaker()
    
    h.huh      // 2
    h.huh = 32 
    h.huh      // 50
    h.huh = 39
    h.huh      // 59
    

    innerVal和mysteriousMath在外面使用时隐藏在这里,并试图挖掘进入对象的方式应该导致错误 .

    我只是通过阅读Swift文档的方式的一部分,所以如果有一个缺陷请指出来,很想知道 .

  • 0

    从Xcode 6 beta 4开始,Swift具有访问修饰符 . 从发行说明:

    Swift访问控制有三个访问级别:私有实体只能从定义它们的源文件中访问 . 内部实体可以在定义它们的目标内的任何位置访问 . 可以从目标内的任何位置以及从导入当前目标模块的任何其他上下文访问公共实体 .

    隐式默认值为 internal ,因此在应用程序目标中,您可以关闭访问修饰符,除非您希望限制更多 . 在框架目标中(例如,如果您要嵌入框架以在应用程序和共享或今日视图扩展之间共享代码),请使用 public 指定要向框架的客户端公开的API .

  • 16

    希望为那些想要类似于受保护方法的人节省一些时间:

    根据其他答案,swift现在提供了'private'修饰符 - 它是按文件方式而不是按类别定义的,例如Java或C#中的修饰符 . 这意味着如果你想要受保护的方法,你可以使用swift私有方法,如果它们在同一个文件中

    • 创建一个基类来保存'protected'方法(实际上是私有的)

    • 这个类的子类使用相同的方法

    • 在其他文件中,即使您是子类,也无法访问基类方法

    例如档案1:

    class BaseClass {
        private func protectedMethod() {
    
        }
    }
    
    class SubClass : BaseClass {
        func publicMethod() {
            self.protectedMethod()  //this is ok as they are in same file
        }
    }
    

    文件2:

    func test() {
        var a = BaseClass()
        a.protectedMethod() //ERROR
    
    
        var b = SubClass()
        b.protectedMethod() //ERROR
    }
    
    class SubClass2 : BaseClass {
        func publicMethod() {
            self.protectedMethod() //ERROR
        }
    

    }

  • 6

    Swift 3.0 provides five different access controls:

    • 打开

    • 公众

    • 内部

    • fileprivate

    • 私人

    开放访问和公共访问使实体可以在其定义模块的任何源文件中使用,也可以在来自导入定义模块的另一个模块的源文件中使用 . 在指定框架的公共接口时,通常使用开放或公共访问 . 内部访问使实体可以在其定义模块的任何源文件中使用,但不能在该模块之外的任何源文件中使用 . 在定义应用程序或框架的内部结构时,通常使用内部访问 . 文件专用访问将实体的使用限制在其自己的定义源文件中 . 当在整个文件中使用这些详细信息时,使用文件专用访问来隐藏特定功能的实现细节 . 私人访问限制实体对封闭声明的使用 . 当这些详细信息仅在单个声明中使用时,使用私有访问来隐藏特定功能的实现细节 . 开放访问是最高(限制性最小)的访问级别,私有访问是最低(限制性最强)的访问级别 .

    Default Access Levels

    如果您没有自己指定显式访问级别,则代码中的所有实体(具有一些特定的例外)都具有内部的默认访问级别 . 因此,在许多情况下,您无需在代码中指定显式访问级别 .

    The release note on the topic:

    声明为public的类不能再在其定义模块之外进行子类化,并且声明为public的方法不能再在其定义模块之外被覆盖 . 要允许外部子类或外部重写的方法,请将它们声明为open,这是一个超出public的新访问级别 . 导入的Objective-C类和方法现在全部导入为open而不是public . 使用@testable导入导入模块的单元测试仍然允许子类化公共或内部类,以及覆盖公共或内部方法 . (SE-0117)

    更多信息和详情:The Swift Programming Language (Access Control)

  • 17

    在Beta 6中,文档指出有三种不同的访问权限修饰符:

    • 公众

    • 内部

    • 私人

    这三个适用于类,协议,函数和属性 .

    public var somePublicVariable = 0
    internal let someInternalConstant = 0
    private func somePrivateFunction() {}
    

    有关更多信息,请查看Access Control .

  • 2

    Xcode 6中引入的访问控制机制:

    Swift为代码中的实体提供三种不同的访问级别 . 这些访问级别与定义实体的源文件相关,也与源文件所属的模块相关 . 公共访问使实体可以在其定义模块的任何源文件中使用,也可以在来自导入定义模块的另一个模块的源文件中使用 . 在指定框架的公共接口时,通常使用公共访问 . 内部访问使实体可以在其定义模块的任何源文件中使用,但不能在该模块之外的任何源文件中使用 . 在定义应用程序或框架的内部结构时,通常使用内部访问 . 专用访问将实体的使用限制在其自己的定义源文件中 . 使用私有访问隐藏特定功能的实现细节 . 公共访问是最高(限制性最小)的访问级别,私有访问是最低(或限制性最强)的访问级别 .

    默认情况下将其加入内部,并且不需要指定 . 另请注意,私有说明符 not 在类级别上工作,但在源文件级别上 . 这意味着要使类的某些部分真正私有,您需要将其分成自己的文件 . 这也介绍了一些有关单元测试的有趣案例......

    我在上面的链接中评论过的另一点是,您无法“升级”访问级别 . 如果你继承了某些东西,你可以更多地限制它,但不能相反 .

    最后一点也会影响函数,元组和其他东西,如果函数使用私有类,那么将函数设置为internal或public是无效的,因为它们可能无法访问私有类 . 这会导致编译器警告,您需要将该函数重新声明为私有函数 .

  • 15

    For Swift 1-3:

    不,这是不可能的 . 根本没有任何私有/受保护的方法和变量 .

    一切都是公开的 .

    Update 自Swift 4以来,可以在这个帖子中看到其他答案

  • 4

    您可以使用的一个选项是将实例创建包装到函数中,并在构造函数中提供适当的getter和setter:

    class Counter {
        let inc: () -> Int
        let dec: () -> Int
    
        init(start: Int) {
            var n = start
    
            inc = { ++n }
            dec = { --n }
        }
    }
    
    
    let c = Counter(start: 10)
    
    c.inc()  // 11
    c.inc()  // 12
    c.dec()  // 11
    
  • -1

    现在处于测试阶段4,他们为Swift添加了访问修饰符 .

    来自Xcode 6 beta 4 realese notes

    Swift访问控制有三个访问级别:私有实体只能在源文件中定义 . 内部实体可以在目标定义的任何地方访问 . 可以从目标内的任何位置以及从导入当前目标模块的任何其他上下文访问公共实体 . 默认情况下,源文件中的大多数实体都具有内部访问权限 . 这允许应用程序开发人员在很大程度上忽略访问控制,同时允许框架开发人员完全控制框架的API .

  • 2

    Swift 3 and 4 也为变量和方法的访问级别带来了很多变化 . Swift 3 and 4 现在有4个不同的访问级别,其中 open/public 访问是最高(限制性最小)访问级别, private 访问是最低(限制性最强)访问级别:

    • private 函数和成员只能在实体本身(struct,class,...)及其扩展的范围内访问(在Swift 3中,扩展也受到限制)

    • fileprivate 函数和成员只能在声明它们的源文件中访问 .

    • internal 函数和成员(默认情况下,如果未明确添加访问级别关键字)可以在定义它们的目标内的任何位置访问 . 这就是为什么TestTarget没有't have automatically access to all sources, they have to be marked as accessible in xCode'的文件检查器 .
      可以从目标内的任何位置以及导入当前目标模块的任何其他上下文访问

    • open or public 函数和成员 .

    Interesting:

    您可以在类/结构的扩展中覆盖一些方法(例如,通常是辅助函数),并将整个扩展标记为“私有”,而不是将每个方法或成员标记为“私有” .

    class foo { }
    
    private extension foo {
        func somePrivateHelperFunction01() { }
        func somePrivateHelperFunction02() { }
        func somePrivateHelperFunction03() { }
    }
    

    这可能是个好主意,以便获得更好的可维护代码 . 而且你可以轻松切换(例如,对于单元测试)通过仅改变一个单词来进行非私有 .

    Apple documentation

  • 9

    直到swift 2.0只有三个访问级别[公共,内部,私有]但是在swift 3.0中苹果添加了两个新的访问级别,它们是[Open,fileType]所以现在在swift 3.0中有5个访问级别这里我要清除角色这两个访问级别1.打开:这与Public非常相似,但唯一的区别是Public可以访问子类并覆盖,而Open访问级别无法访问this image is taken from Medium website and this describe the difference between open and public access

    现在到第二个新的访问级别2. filetype是私有的更大版本或者比内部更少的访问级别fileType可以访问[class,struct,enum]的扩展部分而private不能访问它只能访问的扩展部分代码词汇范围this image is taken from Medium website and this describe the difference between fileType and Private access level

相关问题