Swift有访问修饰符吗?

时间:2014-06-02 21:52:47

标签: access-modifiers swift

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

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

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

19 个答案:

答案 0 :(得分:399)

As of Swift 3.0.1, there are 4 levels of access,从最高(限制最少)到最低(最严格)来描述如下。


1。 openpublic

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

但是, open访问仅适用于类和类成员,并且它与public访问权限不同,如下所示:

  • 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

允许在定义模块(目标)中使用实体。在定义应用程序或框架的内部结构时,通常使用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

将实体的使用限制在其附件声明中。当这些细节仅在单个声明中使用时,您通常使用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

答案 1 :(得分:17)

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

所以我们在这里真正谈论的是一种定义面向公众的界面的方法,该界面仅仅呈现我们想要的功能,并“隐藏”我们认为“私有”的其余部分”

用于声明接口的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中为此目的使用的类扩展。

答案 2 :(得分:17)

Swift 4

根据Swift Documentation - Access Control中提到的, Swift 4 5个访问控制

  • 打开 公开 :可以从其模块的实体访问导入定义模块的任何模块实体。

  • 内部 :只能从其模块的实体访问。这是默认的访问级别。

  • fileprivate 私有 :只能在有限范围内限制访问定义它们。


open public 有什么区别?

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

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


fileprivate private 有什么区别?

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

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

// 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相关的问题,您可以查看this Q&A

答案 3 :(得分:15)

据我所知,没有关键字' public',' private'或者'受保护的'。这表明一切都是公开的。

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

这通常是一种好的设计模式无论如何都要使用;因为它可以让您更改实现类层次结构,同时保持逻辑类型系统不变。

答案 4 :(得分:12)

使用协议,闭包和嵌套/内部类的组合,可以使用模块模式的某些内容来隐藏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文档的一部分,所以如果这里有一个缺陷请指出来,很想知道。

答案 5 :(得分:9)

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

  

Swift访问控制有三个访问级别:

     
      
  • 私有实体只能在定义它们的源文件中访问。
  •   
  • 内部实体可以在定义目标的任何位置访问。
  •   
  • 公共实体可以从目标内的任何位置以及导入当前目标模块的任何其他上下文进行访问。
  •   

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

答案 6 :(得分:6)

Swift 3.0提供了五种不同的访问控制:

  1. 打开
  2. 公共
  3. 内部
  4. fileprivate
  5. 私有
  6.   

    打开访问权限和公共访问权限实体可以在其定义模块的任何源文件中使用,也可以在   来自另一个导入定义模块的模块的源文件。您   通常在指定公共时使用开放或公共访问   框架的接口。

         

    内部访问使实体可以在其定义模块的任何源文件中使用,但不能在任何源文件中使用   模块。您通常在定义应用程序或a时使用内部访问权限   框架的内部结构。

         

    文件专用访问限制将实体用于其自己的定义源文件。使用文件私有访问来隐藏   当那些特定功能的实现细节   详细信息在整个文件中使用。

         

    私有访问权限将实体的使用限制在封闭声明中。使用私有访问来隐藏实现细节   仅在使用这些详细信息时的特定功能   在一份声明中。

         

    打开 访问权限是访问级别最高(限制性最强),私有访问权限是访问级别最低(限制性最强)的访问级别

    默认访问级别

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

    有关主题的发布说明:

      

    声明为public的类不能再在子类之外进行子类化   他们的定义模块和声明为public的方法不再是   在他们的定义模块之外被覆盖。允许课程   声明,外部子类或外部重写的方法   它们是开放的,这是一种超越公众的新访问级别。进口   Objective-C类和方法现在全部导入为open   比公开的。使用@testable导入导入模块的单元测试   仍将被允许继承公共或内部类的子类   作为覆盖公共或内部方法。 (SE-0117)

    更多信息&细节 : The Swift Programming Language (Access Control)

答案 7 :(得分:4)

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

  • 公共
  • 内部
  • 私人

这三个适用于类,协议,功能和属性。

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

有关详情,请查看 Access Control

答案 8 :(得分:3)

访问控制机制为introduced in Xcode 6

  

Swift为代码中的实体提供三种不同的访问级别。这些访问级别与定义实体的源文件相关,也与源文件所属的模块相关。

     
      
  • 公共访问使实体可以在其定义模块的任何源文件中使用,也可以在另一个导入定义模块的模块的源文件中使用。在指定框架的公共接口时,通常使用公共访问。
  •   
  • 内部访问允许实体在其定义模块的任何源文件中使用,但不能在该模块之外的任何源文件中使用。在定义应用程序或框架的内部结构时,通常使用内部访问。
  •   
  • 私有访问将实体的使用限制在其自己的定义源文件中。使用私有访问隐藏特定功能的实现细节。
  •   
     

公共访问是最高(限制性最小)的访问级别,私有访问是最低(或限制性最强)的访问级别。

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

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

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

答案 9 :(得分:2)

您可以使用的一个选项是将实例创建包装到一个函数中,并在构造函数中提供适当的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

答案 10 :(得分:2)

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

来自Xcode 6 beta 4 realese notes

  

Swift访问控制有三个访问级别:

     
      
  • private个实体只能在源文件中定义。
  •   
  • internal个实体可以在目标定位的任何地方访问。
  •   可以从目标内的任何位置和任何其他上下文访问
  • public个实体   导入当前目标的模块。
  •   
     

默认情况下,源文件中的大多数实体都具有内部访问权限。这允许应用程序开发者   在很大程度上忽略访问控制,同时允许框架开发人员完全控制   框架的API。

答案 11 :(得分:2)

对于Swift 1-3:

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

一切都是公开的。

<强>更新 从Swift 4开始,可以在这个帖子中看到其他答案

答案 12 :(得分:2)

Swift 3和4 也为变量和方法的访问级别带来了很多变化。 Swift 3和4 现在有4种不同的访问级别,其中开放/公共访问权限是访问级别最高(限制性最强),私有访问权限是最低(限制性最强)的访问级别:

  • 私有函数和成员只能在实体本身(struct,class,...)及其扩展的范围内访问(在Swift 3中,扩展也受到限制)
  • fileprivate 函数和成员只能在声明它们的源文件中访问。
  • 内部函数和成员(默认情况下,如果未明确添加访问级别关键字)可以在定义它们的目标中的任何位置访问。这就是为什么TestTarget没有自动访问所有来源,必须在xCode的文件检查器中将它们标记为可访问。
  • 开放或公共功能和成员可以从目标内的任何位置以及导入当前目标模块的任何其他上下文进行访问。

<强>有趣:

不是将每个方法或成员标记为&#34; private&#34;,而是可以在类/结构的扩展中覆盖一些方法(例如,通常是辅助函数),并将整个扩展标记为&#34;私人&#34;

class foo { }

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

这可能是个好主意,以便获得更好的可维护代码。您只需更改一个单词即可轻松切换(例如,进行单元测试)非私有。

Apple documentation

答案 13 :(得分:1)

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

答案 14 :(得分:0)

看看下面的图

enter image description here

答案 15 :(得分:0)

enter image description here

从最开放到最受限制的顺序:

  • open,您可以从定义模块任何模块中导入的任何源文件访问open类和类成员该模块。您可以在其定义模块以及导入该模块的任何模块中覆盖open类的子类或覆盖open类成员。

  • public允许与open相同的访问-任何模块中的任何源文件-但具有更多的限制性子类化和覆盖。您只能在相同模块内对public类进行子类化。 public类成员只能被相同模块中的子类覆盖。如果您正在编写框架,则这一点很重要。如果希望该框架的用户能够继承类或重写方法,则必须使其为open

  • internal允许在定义模块中的任何源文件中使用,但不能在该模块外部使用。这是默认访问级别。

  • fileprivate仅允许在定义的源文件中使用。

  • private仅允许从封闭的声明和Swift 4中的new到同一源文件中该声明的任何扩展名使用。

了解更多here

答案 16 :(得分:0)

答案 17 :(得分:0)

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

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

  1. 创建一个基类来保存'protected'方法(实际上是私有的)
  2. 将此类子类化为使用相同的方法
  3. 在其他文件中,即使您继承了
  4. ,也无法访问基类方法

    e.g。文件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
        }
    

    }

答案 18 :(得分:-1)

直到swift 2.0只有三个访问级别[公共,内部,私有] 但在swift 3.0中,苹果添加了两个新的访问级别,它们是[Open,fileType] 现在在swift 3.0中有5个访问级别 在这里,我想清楚这两个访问级别的作用 1.开放:这与公众非常相似,但唯一的区别在于公众    可以访问子类并覆盖,而开放访问级别无法访问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