在 Swift3中区分 filepprivate 和 private 的一个很好的例子是什么

这个 文章有助于理解 Swift 3中新的访问说明符。文中还举例说明了 fileprivateprivate的不同用法。

我的问题是-在一个函数上使用 fileprivate,这个函数只能在这个文件中使用,不是和使用 private一样吗?

39634 次浏览

fileprivate现在就是 private以前所在的位置 快速发布: 可从 相同的源文件。标记为 private的声明现在只能在其声明的词法范围内访问。 所以 privatefileprivate限制更多。

斯威夫特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中,请参阅下面的第二个注释 斯威夫特的变化。

  • 可以从相同的源文件访问文件私有的 bar方法。

注:

  1. 提案 SE-0159-修正私人接达级别建议在 Swift 4中恢复到 Swift 2语义。经过长时间和有争议的讨论,迅速发展邮件列表,建议是 被拒绝了

  2. 提案 SE-0169-改善私有声明和扩展之间的交互建议使 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()
}


}

我喜欢这个,因为它对 IVAR 来说非常简单。

尝试将 filepprivate 更改为 private (反之亦然) ,看看在编译时会发生什么..。

一个实用的经验法则是,对变量、常量、内部结构和只在类/结构的声明中使用的类使用 private。对于扩展中使用的内容,可以使用 filepprivate,这些内容与您的 class/struct 位于同一个文件中,但是位于它们定义的大括号之外(即。词汇范围)。

    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
}
}

我只是画了一个关于 二等兵Filepprivate打开公众人士的示意图

希望能对您有所帮助,有关文字说明请参考 马丁 · R的答案

[更新 Swift 4,5]

enter image description here

在下面的例子中,由 privatefileprivate修改的语言结构的行为似乎完全相同:

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))

我想这是直觉的结论,但是,有例外吗?

致以最诚挚的问候。

尽管@MartinR 和@StephenChen 的回答是完美的,但是 Swift 4改变了一些事情。

Private 现在被认为是声明它的类及其扩展的私有类。

FilePrivate 在该文件中被认为是私有的,无论是定义了变量的类、扩展名,还是同一文件中定义的任何其他类。

在 Swift 4.0中,Private 现在可以在扩展名中访问,但是只能在同一个文件中访问。如果您在其他文件中声明/定义扩展名,那么您的私有变量将无法访问您的扩展名 * *

私人文件
文件私有访问将实体的使用限制为它自己的定义源文件。在整个文件中使用特定功能部分的实现细节时,使用文件私有访问隐藏这些细节。
语法: fileprivate <var type> <variable name>
示例: fileprivate class SomeFilePrivateClass {}


二等兵
私有访问将实体的使用限制为包含声明和该 在同一文件中的声明的扩展。使用私有访问隐藏特定功能部件的实现细节,如果这些细节仅在单个声明中使用。
语法: private <var type> <variable name>
示例: private class SomePrivateClass {}


以下是关于所有访问级别的更多细节: < a href = “ https://developer.apple.com/library/content/document/Swift/Concept/Swift _ Programming _ Language/AccessControl.html”rel = “ noReferrer”> Swift-Access 级别

看看这些图片:
文件: ViewController.swift
这里的扩展名和视图控制器都在同一个文件中,因此可以通过扩展名访问私有变量 testPrivateAccessLevel

enter image description here


文件: TestFile.swift
这里的扩展名和视图控制器都在不同的文件中,因此私有变量 testPrivateAccessLevel在扩展名中不可访问。

enter image description here

enter image description here


这里的类 ViewController2ViewController的一个子类,它们都在同一个文件中。这里私有变量 testPrivateAccessLevel在子类中不可访问,但是 filepprivate 在子类中可以访问。

enter image description here

FilePrivate -访问控制级别在文件中。

Case 1 : 如果我们在同一个类文件中创建扩展名,并尝试访问扩展名允许的 filepprivate 函数或 filepprivate 属性
Case 2 : 如果我们在新文件中创建类的扩展-现在尝试访问 filepprivate 函数或 filepprivate 属性-访问不允许

Private -访问控制级别属于词法范围

大小写1 : 如果属性或函数在类中声明为 private-则作用域默认为类。 Case 2 : 如果在函数体中声明了私有实例-那么实例的作用域被限制在函数体中。

这就是迅捷4的解释。对雨燕三号来说,不同之处在于。迅捷3私人无法访问其扩展,只有 A 类本身可以访问。

enter image description here 在 Swift 4之后,filepprivate 变得有点多余,因为人们通常不会在同一个文件中定义子类。对大多数情况来说,私密就足够了。

更新为 Swift 5

Private vs < strong > 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 文件外部,私有和私有文件都不可访问。