Swift有访问修饰符吗?

Ger*_*osi 268 access-modifiers swift

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

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

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

aka*_*kyy 411

Swift 3.0.1开始,有4个访问级别,从最高(限制最少)到最低(最严格),如下所述.


1. openpublic

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

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

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

// First.framework – A.swift

open class A {}
Run Code Online (Sandbox Code Playgroud)

// First.framework – B.swift

public class B: A {} // ok
Run Code Online (Sandbox Code Playgroud)

// Second.framework – C.swift

import First

internal class C: A {} // ok
Run Code Online (Sandbox Code Playgroud)

// Second.framework – D.swift

import First

internal class D: B {} // error: B cannot be subclassed
Run Code Online (Sandbox Code Playgroud)

2. internal

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

// First.framework – A.swift

internal struct A {}
Run Code Online (Sandbox Code Playgroud)

// First.framework – B.swift

A() // ok
Run Code Online (Sandbox Code Playgroud)

// Second.framework – C.swift

import First

A() // error: A is unavailable
Run Code Online (Sandbox Code Playgroud)

3. fileprivate

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

// First.framework – A.swift

internal struct A {

    fileprivate static let x: Int

}

A.x // ok
Run Code Online (Sandbox Code Playgroud)

// First.framework – B.swift

A.x // error: x is not available
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

  • 有人可以向我解释为什么这不是一个大问题? (37认同)
  • 我个人不喜欢像下划线/特殊字符领先的"私人"方法那样的解决方案.即使我保证我自己也是唯一一个看过这段代码的人,它会使代码更加节省/更不容易出错,因为编译器会阻止你做你不应该做的事情.所以我认为他们应该尽快摆脱"访问控制机制",这样人们就不会习惯于坏习惯. (19认同)
  • _always_是OOP中的一些应该是私有或受保护的方法或变量.这允许实现[SOLID设计](http://en.wikipedia.org/wiki/SOLID_(object-oriented_design)),因为大方法被分成许多较小的方法,每个方法都有自己的责任,可以是覆盖,但只有"主"方法应该可供公众使用. (15认同)
  • Xcode 6测试版发行说明:"此种子中未启用访问控制(公共/私人成员)."(15747445)" (10认同)
  • @alcalde公共界面的想法非常有价值.如果您打算将类中的所有代码都驻留在属于公共API的函数中,我认为这是非常有限的.另一方面,拥有指定的公共API允许实现更改(包括使用私有方法)而不会中断使用者.如果某人'需要'使用内部类方法,我觉得他们误解了类的功能限制(或者试图使用错误的类). (9认同)
  • @alcalde你是对的,我们无法预测.用户甚至可以改变源文件,将`protected`更改为`public`.但这并不意味着访问修饰符是无用的.这就像是说注释方法的返回类型是没用的*(如果它不适用于编译器)*,因为方法可以返回它想要的任何东西.访问修饰符是清晰可读API的重要组成部分,就像类型注释一样. (2认同)

Ahm*_*d F 21

斯威夫特4

正如Swift文档中提到的- 访问控制,Swift 45个访问控制:

  • open public:可以从模块的实体和导入定义模块的任何模块实体访问.

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

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



开放公共有什么区别?

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

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


fileprivateprivate有什么区别?

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!"
    }
}
Run Code Online (Sandbox Code Playgroud)


Swift 3和Swift 4 Access Control有什么区别?

正如SE-0169提案中所提到的,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!
    }
}
Run Code Online (Sandbox Code Playgroud)

所以,没有必要宣布myMessagefileprivate是在整个文件进行访问.

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


jem*_*ons 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)"
  }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

var myClass:MyClass = MyClassImplementation()
Run Code Online (Sandbox Code Playgroud)

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


Ian*_*ose 15

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

然而,Apple可能期望人们使用" 协议 "(世界其他地方称为接口)和工厂设计模式来隐藏实现类型的细节.

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

  • 如果有一种方法来隐藏协议的实现类,那将会更好,但似乎没有. (4认同)

Dav*_*app 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
Run Code Online (Sandbox Code Playgroud)

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

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

  • 仍然可以访问:P`selected(h)[0] .1.value // 19` (8认同)
  • 很高兴找到约翰 - 我不知道反思.似乎把对象变成了元组 - 在Swift中有关于该函数或其他元编程的东西的官方文档吗?我浏览了iBooks上的语言指南,但我没有看到它. (2认同)

ric*_*ter 9

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

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

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

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


Cry*_*ppo 6

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

  1. 打开
  2. 上市
  3. 内部
  4. fileprivate
  5. 私人的

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

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

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

私人访问限制实体对封闭声明的使用.当这些详细信息仅在单个声明中使用时,使用私有访问来隐藏特定功能的实现细节.

开放访问是最高(限制性最小)的访问级别,私有访问是最低(限制性最强)的访问级别.

默认访问级别

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

关于该主题的发行说明:

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

更多信息和细节: Swift编程语言(访问控制)