在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中数据的可见性?
在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中数据的可见性?
Answers:
从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具有5个访问控制:
打开和public:可以从其模块的实体以及导入定义模块的任何模块的实体中进行访问。
internal:只能从其模块的实体访问。这是默认的访问级别。
文件私有和私有:只能在定义它们的有限范围内有限地访问。
open与以前的Swift版本中的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或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中为此目的使用的类扩展。
据我所知,没有关键字“ public”,“ private”或“ protected”。这表明一切都是公开的。
但是,苹果可能希望人们使用“ 协议 ”(世界其他地方称为接口)和工厂设计模式来隐藏实现类型的细节。
无论如何,这通常是一个好的设计模式。因为它可以让您更改实现类层次结构,同时保持逻辑类型系统相同。
结合使用协议,闭包和嵌套/内部类,可以立即在模块模式中使用某些东西在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和mysteryMath在这里被外部使用隐藏了,尝试深入研究该对象会导致错误。
我只是阅读Swift文档的一部分,因此,如果有缺陷,请指出,希望知道。
reflect(h)[0].1.value // 19
从Xcode 6 beta 4开始,Swift具有访问修饰符。从发行说明中:
Swift访问控制具有三个访问级别:
- 私有实体只能从定义它们的源文件中访问。
- 内部实体可以在定义它们的目标内的任何地方访问。
- 可以从目标内的任何位置以及导入当前目标模块的任何其他上下文中访问公共实体。
隐式默认值是internal
,因此在应用程序目标中,您可以保留访问修饰符,除非您希望限制更多。在框架目标中(例如,如果要嵌入框架以在应用程序和共享或“今日”视图扩展之间共享代码),请使用public
来指定要向框架的客户公开的API。
Swift 3.0提供了五种不同的访问控制:
开放访问和公共访问使实体可以在其定义模块的任何源文件中使用,也可以在导入定义模块的另一个模块的源文件中使用。指定框架的公共接口时,通常使用开放访问或公共访问。
内部访问使实体可以在其定义模块的任何源文件中使用,但不能在该模块外部的任何源文件中使用。在定义应用程序或框架的内部结构时,通常使用内部访问。
文件专用访问将实体的使用限制为自己定义的源文件。当在整个文件中使用特定功能的实现细节时,使用文件私有访问权限可以隐藏这些细节。
专用访问将实体的使用限制为包含在声明中。当仅在单个声明中使用特定功能的实现细节时,请使用私有访问权限来隐藏这些细节。
开放访问是最高(最低限制)访问级别,而私有访问是最低(最高限制)访问级别。
默认访问级别
如果您自己未指定显式访问级别,则代码中的所有实体(有一些特定的例外)都具有默认的内部访问级别。因此,在许多情况下,您无需在代码中指定显式访问级别。
关于该主题的发行说明:
声明为public的类不能再在其定义模块之外进行子类化,并且声明为public的方法不能再在其定义模块之外进行重写。为了允许类在外部被子类化或方法在外部被重写,请将它们声明为open,这是超越public的新访问级别。现在,导入的Objective-C类和方法都以开放方式而不是公共方式导入。使用@testable导入来导入模块的单元测试仍将被允许子类化public或内部类,以及重写public或内部方法。(SE-0117)
详细信息和详细信息: Swift编程语言(访问控制)
现在在Beta 4中,他们为Swift添加了访问修饰符。
Swift访问控制具有三个访问级别:
private
实体只能从定义它们的源文件中访问。internal
可以在定义对象的目标中的任何位置访问实体。public
可以从目标内的任何位置以及导入当前目标模块的任何其他上下文中访问实体。默认情况下,源文件中的大多数实体都具有内部访问权限。这允许应用程序开发人员在很大程度上忽略访问控制,同时允许框架开发人员完全控制框架的API。
Swift为代码中的实体提供了三种不同的访问级别。这些访问级别与定义实体的源文件有关,也与源文件所属的模块有关。
- 公共访问使实体可以在其定义模块的任何源文件中使用,也可以在导入定义模块的另一个模块的源文件中使用。指定框架的公共接口时,通常使用公共访问权限。
- 内部访问使实体可以在其定义模块的任何源文件中使用,但不能在该模块外部的任何源文件中使用。在定义应用程序或框架的内部结构时,通常使用内部访问。
- 专用访问将实体的使用限制为自己定义的源文件。使用私有访问权限可以隐藏特定功能的实现细节。
公共访问是最高(最低限制)访问级别,而私有访问是最低(或最高限制)访问级别。
缺省将其内部访问,并且不需要指定。还要注意的是,私人符确实没有工作的一流水平,但在源文件级别。这意味着要使某个类的各个部分真正私有,您需要将其分成一个单独的文件。这也介绍了一些有关单元测试的有趣案例。
在上面的链接中对我说的另一点是,您不能“升级”访问级别。如果您将某些子类化,则可以对其进行更多限制,但不能反过来。
最后一点也会影响函数,元组以及其他肯定会影响其他东西的方式,例如,如果一个函数使用私有类,那么拥有内部或公共函数是无效的,因为它们可能无法访问私有类。这会导致编译器警告,因此您需要将该函数重新声明为私有函数。
Swift 3和Swift 4也为变量和方法的访问级别带来了很多变化。Swift 3和Swift 4现在具有4种不同的访问级别,其中开放/公共访问是最高(最低限制)访问级别,而私有访问是最低(最高限制性)访问级别:
有趣:
不必将每个方法或成员都标记为“私有”,而是可以在类/结构的扩展中介绍某些方法(例如,典型的辅助函数),并将整个扩展标记为“私有”。
class foo { }
private extension foo {
func somePrivateHelperFunction01() { }
func somePrivateHelperFunction02() { }
func somePrivateHelperFunction03() { }
}
为了获得更好的可维护代码,这可能是一个好主意。您只需更改一个词就可以轻松地将其切换为非私有(例如,用于单元测试)。
对于Swift 1-3:
不,不可能。根本没有任何私有/受保护的方法和变量。
一切都是公开的。
自Swift 4起更新,有可能在此线程中看到其他答案
您可以使用的选项之一是将实例创建包装到函数中,并在构造函数中提供适当的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
希望为那些想要类似于受保护方法的人节省一些时间:
根据其他答案,swift现在提供了“专用”修饰符-它是按文件而不是按类定义的,例如Java或C#中的那些。这意味着,如果要使用受保护的方法,则可以使用快速私有方法(如果它们在同一个文件中)
例如文件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
}
}
在swift 2.0之前,只有三个访问级别[公共,内部,私有],但是在swift 3.0中,苹果添加了两个新的访问级别,分别是[Open,fileType],因此在swift 3.0中现在有5个访问级别在这里我想清除角色这两个访问级别中的第一个。1. Open:这与Public非常相似,但是唯一的区别是Public可以访问子类并重写,而Open访问级别则不能访问 该图像取自Medium网站,并且这描述了区别在开放和公共访问之间
现在进入第二个新的访问级别2。filetype是private的更大版本,或者比内部访问级别小。fileType可以访问[class,struct,enum]的扩展部分,而private无法访问代码的扩展部分,它只能访问该图像的词法范围 是从Medium网站获取的,它描述了fileType和Private访问级别之间的区别