什么是区分 Swift3 中的 fileprivate 和 private 的好例子

What is a good example to differentiate between fileprivate and private in Swift3

article 有助于理解 Swift 3 中的新访问说明符。它还给出了 fileprivateprivate 的不同用法的一些示例。

我的问题是 - 在将仅在此文件中使用的函数上使用 fileprivate 是否与使用 private 相同?

fileprivate 现在是 private 以前的样子 Swift 版本:可从 同一个源文件。标记为 private 的声明现在只能在其声明的词法范围内访问。 所以 privatefileprivate.

更具限制性

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 方法可从同一源文件访问。

备注:

  1. 提案SE-0159 – Fix Private Access Levels suggested to revert to the Swift 2 semantics in Swift 4. After a lengthy and controversial discussion on the swift-evolution mailing list, the proposal was rejected.

  2. 提案SE-0169 – Improve Interaction Between private Declarations and Extensions建议制作private 同一类型的扩展可访问的类型内的声明 如果扩展名在 相同的源文件中定义。 该提议在 Swift 4.

  3. 中被接受并实施
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(反之亦然),看看编译时会发生什么...

一个实用的经验法则是,您对仅在 class / 结构的声明中使用的变量、常量、内部结构和 classes 使用 private。您将 fileprivate 用于与 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
        }
    }

我只是画了一个关于privatefileprivateopen和[=19的图=]public

希望能尽快帮到您,文字说明请参考Martin R的回答

[更新 Swift 4, 5 ]

在以下示例中,由 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 现在被认为是声明它的 class 及其扩展的私有。

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

在 Swift 4.0 中,Private 现在可以在扩展中访问,但在同一文件中。如果您在其他文件中 declare/define 扩展名,那么您的扩展名将无法访问您的私有变量**

文件私有
文件私有访问将实体的使用限制在其自己的定义源文件中。当在整个文件中使用这些细节时,使用文件私有访问来隐藏特定功能的实现细节。
语法: 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在扩展中不可访问。


这里 class ViewController2ViewController 的子 class 并且都在同一个文件中。这里私有变量 testPrivateAccessLevel 在 Subclass 中不可访问,但 fileprivate 在 subclass.

中可访问

filePrivate - 访问控制级别在文件内。

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

private - 访问控制级别在词法范围内

案例 1:如果 属性 或函数在 class 中声明为私有 - 那么范围默认为 class。 案例 2:如果在函数体中声明了私有实例 - 那么实例的范围仅限于函数体。

这是对swift4的解释,对于swift3,区别是私有的。 swift3 private不能被其扩展访问,只有ClassA本身可以访问

swift4之后,fileprivate就变得有点多余了,因为人们一般不会在同一个文件中定义子类。对于大多数情况,私有应该足够了。

更新 Swift 5

Private 对比 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 文件之外,私有文件和私有文件都不可访问。