在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中数据的可见性?
答案 0 :(得分:399)
As of Swift 3.0.1, there are 4 levels of access,从最高(限制最少)到最低(最严格)来描述如下。
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
答案 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 Documentation - Access Control中提到的, Swift 4 有 5个访问控制:
打开 和 公开 :可以从其模块的实体访问导入定义模块的任何模块实体。
内部 :只能从其模块的实体访问。这是默认的访问级别。
fileprivate 和 私有 :只能在有限范围内限制访问定义它们。
open 与以前版本的Swift中的public相同,它们允许来自其他模块的类使用和继承它们,即:它们可以从其他模块中继承。此外,它们允许来自其他模块的成员使用和覆盖它们。他们的模块也采用相同的逻辑。
public 允许来自其他模块的类使用它们,但不继承它们,即:它们不能从其他模块中继承。此外,它们允许来自其他模块的成员使用它们,但不要覆盖它们。对于他们的模块,它们具有相同的开放逻辑(它们允许类使用和继承它们;它们允许成员使用和覆盖它们。)
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!"
}
}
正如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提供了五种不同的访问控制:
打开访问权限和公共访问权限实体可以在其定义模块的任何源文件中使用,也可以在 来自另一个导入定义模块的模块的源文件。您 通常在指定公共时使用开放或公共访问 框架的接口。
内部访问使实体可以在其定义模块的任何源文件中使用,但不能在任何源文件中使用 模块。您通常在定义应用程序或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)
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种不同的访问级别,其中开放/公共访问权限是访问级别最高(限制性最强),私有访问权限是最低(限制性最强)的访问级别:
<强>有趣:强>
不是将每个方法或成员标记为&#34; private&#34;,而是可以在类/结构的扩展中覆盖一些方法(例如,通常是辅助函数),并将整个扩展标记为&#34;私人&#34;
class foo { }
private extension foo {
func somePrivateHelperFunction01() { }
func somePrivateHelperFunction02() { }
func somePrivateHelperFunction03() { }
}
这可能是个好主意,以便获得更好的可维护代码。您只需更改一个单词即可轻松切换(例如,进行单元测试)非私有。
答案 13 :(得分:1)
language grammar没有关键字'public','private'或'protected'。这表明一切都是公开的。当然,可以有一些替代方法来指定没有这些关键字的访问修饰符,但我在语言参考中找不到它。
答案 14 :(得分:0)
答案 15 :(得分:0)
从最开放到最受限制的顺序:
open
,您可以从定义模块或任何模块中导入的任何源文件访问open
类和类成员该模块。您可以在其定义模块以及导入该模块的任何模块中覆盖open
类的子类或覆盖open
类成员。
public
允许与open
相同的访问-任何模块中的任何源文件-但具有更多的限制性子类化和覆盖。您只能在相同模块内对public
类进行子类化。 public
类成员只能被相同模块中的子类覆盖。如果您正在编写框架,则这一点很重要。如果希望该框架的用户能够继承类或重写方法,则必须使其为open
。
internal
允许在定义模块中的任何源文件中使用,但不能在该模块外部使用。这是默认访问级别。
fileprivate
仅允许在定义的源文件中使用。
private
仅允许从封闭的声明和Swift 4中的new到同一源文件中该声明的任何扩展名使用。
了解更多here
答案 16 :(得分:0)
启动SWIFT 2.2;)
默认为内部
答案 17 :(得分:0)
希望为那些想要类似于受保护方法的人节省一些时间:
根据其他答案,swift现在提供了'private'修饰符 - 它是按文件方式而不是按类别定义的,例如Java或C#中的修饰符。这意味着如果你想要受保护的方法,你可以使用swift私有方法,如果它们在同一个文件中
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