在Swift3中区分fileprivate和private之间有什么好的例子

问题描述 投票:131回答:10

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

我的问题是 - 是不是在一个函数上使用fileprivate只会在这个文件中使用private

swift swift3 private access-control access-specifier
10个回答
271
投票

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建议恢复Swift 4中的Swift 2语义。经过对swift-evolution邮件列表的冗长而有争议的讨论,该提案是rejected
  2. 提议SE-0169 – Improve Interaction Between private Declarations and Extensions建议如果扩展名在同一源文件中定义,则在相同类型的扩展可访问的类型内部进行private声明。该提案在Swift 4中被接受并实施。

1
投票
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(反之亦然),看看编译时会发生什么......


77
投票

我只是绘制一个关于private,fileprivate,open和public的图表

希望它可以快速帮助你,对于文字描述请参考Martin R的回答

[更新Swift 4]

enter image description here


6
投票

一个实际的经验法则是对变量,常量,内部结构和仅在类/结构声明中使用的类使用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
        }
    }

5
投票

在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不能在扩展中访问。

这里的类ViewController2ViewController的子类,两者都在同一个文件中。这里私有变量testPrivateAccessLevel在子类中不可访问,但fileprivate可在子类中访问。


4
投票

尽管@ MartinR和@ StephenChen的答案是完美的,但Swift 4改变了一些东西。

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

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


3
投票

在下面的示例中,由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))

我猜这是根据直觉。但是,有什么例外吗?

最亲切的问候。


2
投票

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

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

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

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


2
投票

这是swift 4的解释。对于swift 3,区别在于私有。 swift 3 private无法通过其扩展访问,只有A类本身才能访问。

enter image description here在swift 4之后,fileprivate变得有点多余,因为人通常不会在同一个文件中定义子类。对于大多数情况,私人应该足够了。


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。

© www.soinside.com 2019 - 2024. All rights reserved.