在Objective-C实例中,数据可以是公共的、受保护的或私有的。例如:
@interface Foo : NSObject
{
@public
int x;
@protected:
int y;
@private:
int z;
}
-(int) apple;
-(int) pear;
-(int) banana;
@end
我没有发现任何提到的访问修饰符在Swift参考。是否有可能限制Swift中数据的可见性?
在Objective-C实例中,数据可以是公共的、受保护的或私有的。例如:
@interface Foo : NSObject
{
@public
int x;
@protected:
int y;
@private:
int z;
}
-(int) apple;
-(int) pear;
-(int) banana;
@end
我没有发现任何提到的访问修饰符在Swift参考。是否有可能限制Swift中数据的可见性?
当前回答
语言语法没有关键字“public”,“private”或“protected”。这意味着一切都是公开的。当然,可以有一些替代方法来指定没有这些关键字的访问修饰符,但我在语言参考中找不到它。
其他回答
从Swift 3.0.1开始,共有4个访问级别,从最高(限制最少)到最低(限制最多)。
1. 公开和公共
允许在定义模块(目标)之外使用一个实体。在指定框架的公共接口时,通常使用开放或公共访问。
然而,开放访问仅适用于类和类成员,它与公共访问的区别如下:
公共类和类成员只能在定义模块(目标)内进行子类化和重写。 开放类和类成员可以在定义模块(目标)内外被子类化和重写。
// 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. 内部
启用在定义模块(目标)中使用的实体。在定义应用程序或框架的内部结构时,通常使用内部访问。
// 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
将实体的使用限制到其定义的源文件。当在整个文件中使用特定功能块的实现细节时,通常使用文件私有访问来隐藏这些细节。
// 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. 私人
将实体的使用限制在其封闭声明范围内。当只在单个声明中使用特定功能块的实现细节时,通常使用私有访问来隐藏这些细节。
// 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或ObjC(或ruby或java或…)中创建“私有方法”时,这些方法并不是真正的私有方法。他们周围没有实际的访问控制。任何语言只要能够提供一点内省功能,就可以让开发人员从类之外获得这些值,如果他们真的想要的话。
因此,我们在这里真正谈论的是一种定义面向公众的接口的方法,该接口仅呈现我们想要的功能,并“隐藏”其余我们认为是“私有”的功能。
Swift声明接口的机制就是协议,它可以用于此目的。
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中为此目的使用的类扩展。
对于Swift 1-3:
不,不可能。这里根本没有任何私有/受保护的方法和变量。
一切都是公开的。
更新 从Swift 4开始,可能会在这个帖子中看到其他答案
希望为那些想要类似保护方法的人节省一些时间:
与其他答案一样,swift现在提供了“private”修饰符——它是按文件定义的,而不是像Java或c#那样按类定义的。这意味着如果你想要受保护的方法,如果它们在同一个文件中,你可以使用swift私有方法
创建一个基类来保存“受保护的”方法(实际上是私有的) 子类化这个类以使用相同的方法 在其他文件中,您不能访问基类方法,即使您创建了子类
文件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
}
}
你可以使用的一个选项是将实例创建包装到一个函数中,并在构造函数中提供适当的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