这个article有助于理解Swift 3
中的新访问说明符。它还给出了fileprivate
和private
的不同用法的一些例子。
我的问题是 - 是不是在一个函数上使用fileprivate
只会在这个文件中使用private
?
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 { ... }
定义的范围内访问。它甚至无法从类型的扩展访问(在Swift 3中,请参阅下面的第二个注释,了解Swift 4中的更改)。bar
方法。笔记:
private
声明。该提案在Swift 4中被接受并实施。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用于与您的类/结构相同的文件中的扩展内部使用的内容,但在其定义的花括号之外(即它们的词法范围)。
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 - Access Levels
看看这张图片:
文件:ViewController.swift
这里扩展和视图控制器都在同一个文件中,因此可以扩展访问私有变量testPrivateAccessLevel
文件:TestFile.swift
这里扩展和视图控制器都在不同的文件中,因此私有变量testPrivateAccessLevel
不能在扩展中访问。
这里的类ViewController2
是ViewController
的子类,两者都在同一个文件中。这里私有变量testPrivateAccessLevel
在子类中不可访问,但fileprivate可在子类中访问。
尽管@ MartinR和@ StephenChen的答案是完美的,但Swift 4改变了一些东西。
Private现在被认为是声明它的类的私有,也是它的扩展。
FilePrivate在该文件中被认为是私有的,无论是定义变量的类,它的扩展名,还是在同一文件中定义的任何其他类。
在下面的示例中,由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))
我猜这是根据直觉。但是,有什么例外吗?
最亲切的问候。
filePrivate - 访问控制级别在文件中。
案例1:如果我们在同一个类文件中创建扩展并尝试在其扩展中访问fileprivate函数或fileprivate属性 - 允许访问 案例2:如果我们在新文件中创建类的扩展 - 现在尝试访问fileprivate函数或fileprivate属性 - 不允许访问
私有 - 访问控制级别在词法范围内
情况1:如果属性或函数在类中声明为私有 - 那么范围默认为类。情况2:如果在函数体中声明了私有实例 - 那么实例的范围仅限于函数体。
更新了Swift 5
Private 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。