在Objective-C实例中,数据可以是public
,protected
或private
.例如:
@interface Foo : NSObject { @public int x; @protected: int y; @private: int z; } -(int) apple; -(int) pear; -(int) banana; @end
我没有在Swift参考中找到任何访问修饰符.是否可以限制Swift中数据的可见性?
从Swift 3.0.1开始,有4个访问级别,从最高(限制最少)到最低(最严格),如下所述.
open
和public
允许在定义模块(目标)之外使用实体.在指定框架的公共接口时,通常使用open
或public
访问.
但是,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
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
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
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
正如Swift文档中提到的- 访问控制,Swift 4有5个访问控制:
open和 public:可以从模块的实体和导入定义模块的任何模块实体访问.
internal:只能从其模块的实体访问.这是默认的访问级别.
fileprivate和 private:只能在您定义它们的有限范围内限制访问.
open与以前版本的Swift中的public相同,它们允许来自其他模块的类使用和继承它们,即:它们可以从其他模块中继承.此外,它们允许来自其他模块的成员使用和覆盖它们.他们的模块也采用相同的逻辑.
public允许来自其他模块的类使用它们,但不能继承它们,即:它们不能从其他模块中继承.此外,它们允许来自其他模块的成员使用它们,但不要覆盖它们.对于他们的模块,它们具有相同的开放逻辑(它们允许类使用和继承它们;它们允许成员使用和覆盖它们).
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!" } }
正如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! } }
所以,没有必要宣布myMessage
为fileprivate是在整个文件进行访问.
补充说明:如果您遇到与未使用迁移的旧Swift 3项目编译Swift 4相关的问题,您可以查看此问答.
据我所知,没有关键字'public','private'或'protected'.这表明一切都是公开的.
然而,Apple可能期望人们使用" 协议 "(世界其他地方称为接口)和工厂设计模式来隐藏实现类型的细节.
无论如何,这通常是一种很好的设计模式; 因为它允许您更改实现类层次结构,同时保持逻辑类型系统相同.
Swift 3.0提供五种不同的访问控制:
打开
上市
内部
fileprivate
私人的
开放访问和公共访问使实体可以在其定义模块的任何源文件中使用,也可以在来自导入定义模块的另一个模块的源文件中使用.在指定框架的公共接口时,通常使用开放或公共访问.
内部访问使实体可以在其定义模块的任何源文件中使用,但不能在该模块之外的任何源文件中使用.在定义应用程序或框架的内部结构时,通常使用内部访问.
文件专用访问将实体的使用限制在其自己的定义源文件中.当在整个文件中使用这些详细信息时,使用文件专用访问来隐藏特定功能的实现细节.
私人访问限制实体对封闭声明的使用.当这些详细信息仅在单个声明中使用时,使用私有访问来隐藏特定功能的实现细节.
开放访问是最高(限制性最小)的访问级别,私有访问是最低(限制性最强)的访问级别.
默认访问级别
如果您没有自己指定显式访问级别,则代码中的所有实体(具有一些特定的例外)都具有内部的默认访问级别.因此,在许多情况下,您无需在代码中指定显式访问级别.
关于该主题的发行说明:
声明为public的类不能再在其定义模块之外进行子类化,并且声明为public的方法不能再在其定义模块之外被覆盖.要允许外部子类或外部重写的方法,请将它们声明为open,这是一个超出public的新访问级别.导入的Objective-C类和方法现在全部导入为open而不是public.使用@testable导入导入模块的单元测试仍然允许子类化公共或内部类,以及覆盖公共或内部方法.(SE-0117)
更多信息和细节: Swift编程语言(访问控制)
使用协议,闭包和嵌套/内部类的组合,可以使用模块模式的某些内容来隐藏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文档的方式的一部分,所以如果有一个缺陷请指出来,很想知道.
从Xcode 6 beta 4开始,Swift具有访问修饰符.从发行说明:
Swift访问控制有三个访问级别:
私有实体只能从定义它们的源文件中访问.
内部实体可以在定义它们的目标内的任何位置访问.
可以从目标内的任何位置以及从导入当前目标模块的任何其他上下文访问公共实体.
隐式默认值是internal
,因此在应用程序目标中,您可以关闭访问修饰符,除非您希望更具限制性.在框架目标中(例如,如果您要嵌入框架以在应用程序和共享或今日视图扩展之间共享代码),请使用public
指定要向框架的客户端公开的API.
当谈到在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中用于此目的的类扩展.