Answers:
fileprivate
现在是private
Swift早期发行版中的版本:可从同一源文件访问。private
现在,只能在声明的词法范围内访问标记为的声明。因此private
比更具限制性fileprivate
。
从Swift 4开始,如果扩展名是在同一源文件中定义的,则同一类型的扩展名可以访问类型内的私有声明。
示例(全部在一个源文件中):
class A {
private func foo() {}
fileprivate func bar() {}
func baz() {
foo()
bar()
}
}
extension A {
func test() {
foo() // Swift 3: error: use of unresolved identifier 'foo'
// Swift 4: no error because extension is in same source file
bar()
}
}
let a = A()
a.foo() // error: 'foo' is inaccessible due to 'private' protection level
a.bar()
foo
仅在class A { ... }
定义范围内才能访问private 方法。从扩展名到类型都无法访问它(在Swift 3中,有关Swift 4中的更改,请参见下面的第二个注释)。
文件专用 bar
可以从同一源文件访问方法。
笔记:
提案SE-0159 –修正专用访问级别建议在Swift 4中恢复到Swift 2语义。在对swift-evolution邮件列表进行了冗长而有争议的讨论之后,该提案是拒绝。
提案SE-0169 –改善私有声明和扩展之间的相互作用建议,private
如果扩展在同一源文件中定义,则使该类型内的声明可用于同一类型的扩展。
该建议已在Swift 4中接受并实施。
foo()
通话。
fileprivate
不是链接到扩展名而是链接到文件(在另一个文件中写入A类扩展名将不允许使用fileprivate
成员)
public
则将不允许您继承,因此第三张图像不正确。另外,如果可以看到任何类,都可以随时对其进行扩展。当时,解释扩展的可视性不是一个好主意。
一条实用的经验法则是,对于变量,常量,内部结构和仅在类/结构的声明内使用的类,请使用private。您将fileprivate用于与您的类/结构相同的文件中,但在其定义的花括号(即其词法范围)之外的扩展内部使用的内容。
class ViewController: UIViewController {
@IBOutlet var tableView: UITableView!
//This is not used outside of class Viewcontroller
private var titleText = "Demo"
//This gets used in the extension
fileprivate var list = [String]()
override func viewDidLoad() {
navigationItem.title = titleText
}
}
extension ViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return list.count
}
}
在Swift 4.0中,现在可以在扩展名中访问Private,但可以在同一文件中访问。如果您在其他文件中声明/定义扩展名,则扩展名将无法访问您的私有变量**
文件专用
文件专用访问将实体的使用限制为自己定义的源文件。当在整个文件中使用特定功能的实现细节时,使用文件专用访问权限可以隐藏这些细节。
语法: fileprivate <var type> <variable name>
示例: fileprivate class SomeFilePrivateClass {}
私有
私有访问将实体的使用限制为封闭的声明以及同一文件中该声明的扩展名。仅在单个声明中使用特定细节的实现细节时,使用私有访问权限可以隐藏这些细节。
语法: private <var type> <variable name>
示例: private class SomePrivateClass {}
以下是有关所有访问级别的更多详细信息:Swift-访问级别
看这张图:
File: ViewController.swift
这里扩展名和视图控制器都在同一个文件中,因此私有变量testPrivateAccessLevel
可以在扩展名中访问
文件: TestFile.swift
这里扩展名和视图控制器都在不同的文件中,因此testPrivateAccessLevel
扩展名中不能访问私有变量。
这里的类ViewController2
是的子类,ViewController
并且都在同一个文件中。在这里,私有变量testPrivateAccessLevel
在子类中不可访问,但fileprivate在子类中可访问。
已为Swift 5更新
私人 vs FilePrivate
为了更清晰,将代码段粘贴到Playground中
class Sum1 {
let a: Int!
let b: Int!
private var result: Int?
fileprivate var resultt: Int?
init(a : Int, b: Int) {
self.a = a
self.b = b
}
func sum(){
result = a + b
print(result as! Int)
}
}
let aObj = Sum1.init(a: 10, b: 20)
aObj.sum()
aObj.resultt //File Private Accessible as inside same swift file
aObj.result //Private varaible will not be accessible outside its definition except extensions
extension Sum1{
func testing() {
// Both private and fileprivate accessible in extensions
print(result)
print(resultt)
}
}
//If SUM2 class is created in same file as Sum1 ---
class Sum2{
func test(){
let aSum1 = Sum1.init(a: 2, b: 2)
// Only file private accessible
aSum1.resultt
}
}
注意:在Swift文件之外,private和fileprivate均不可访问。
filePrivate访问控制级别在文件内。
情况1:如果我们在同一个类文件中创建扩展名,并尝试访问其扩展名中的fileprivate函数或fileprivate属性-允许访问
情况2:如果我们在新文件中创建类的扩展名,然后尝试访问fileprivate函数或fileprivate属性-不允许访问
私人的 -访问控制级别在词法范围内
情况1:如果在类中将属性或函数声明为私有,那么默认情况下,作用域是该类。 情况2:如果私有实例是在函数体中声明的,则实例的范围仅限于函数体。
在下面的例子中,语言结构修改通过private
并fileprivate
似乎行为相同:
fileprivate func fact(_ n: Int) -> Int {
if (n == 0) {
return 1
} else {
return n * fact(n - 1)
}
}
private func gauss(_ n: Int) -> Int {
if (n == 0) {
return 0
} else {
return n + gauss(n - 1)
}
}
print(fact(0))
print(fact(5))
print(fact(3))
print(gauss(10))
print(gauss(9))
我猜这是根据直觉。但是,有什么例外吗?
最亲切的问候。
class Privacy {
fileprivate(set) var pu:Int {
get {
return self.pr
}
set {
self.pr = newValue
}
}
private var pr:Int = 0
fileprivate var fp:Int = 0
func ex() {
print("\(self.pu) == \(self.pr) and not \(self.fp)")
}
}
extension Privacy {
func ex2() {
self.pu = 5
self.ex()
}
}
我喜欢这个,因为它对ivars非常简单。
尝试将fileprivate更改为private(反之亦然),然后查看编译时会发生什么...
private
变为fileprivate
。但是,如果您有手工做的奢侈品,那么通常可以从中受益,private
因为private
它可以编译,一切都很好。