在Swift3中区分文件私有和私有的好例子


142

文章已在了解新的访问说明很有帮助Swift 3。它也给出了不同用途的一些例子fileprivateprivate

我的问题是-不是fileprivate在仅将在此文件中使用的功能上与using一起使用private吗?

Answers:


282

fileprivate现在是privateSwift早期发行版中的版本:可从同一源文件访问。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可以从同一源文件访问方法。

笔记:

  1. 提案SE-0159 –修正专用访问级别建议在Swift 4中恢复到Swift 2语义。在对swift-evolution邮件列表进行了冗长而有争议的讨论之后,该提案是拒绝

  2. 提案SE-0169 –改善私有声明和扩展之间的相互作用建议,private 如果扩展在同一源文件中定义,则使该类型内的声明可用于同一类型的扩展 该建议已在Swift 4中接受并实施。


2
如果您将代码自动从Swift 2转换为3,则Xcode将private变为fileprivate。但是,如果您有手工做的奢侈品,那么通常可以从中受益,private因为private它可以编译,一切都很好。
Dan Rosenstark

@DanielLarsson:有关您的编辑建议:两条评论均适用于foo()通话。
Martin R

82

我只是画了一个关于privatefileprivateopenpublic的图表

希望它能对您有所帮助,有关文字说明,请参阅Martin R的答案

[更新Swift 4]

在此处输入图片说明


9
当心,fileprivate不是链接到扩展名而是链接到文件(在另一个文件中写入A类扩展名将不允许使用fileprivate成员)
Vince

1
这似乎不正确。您错过了关键点。您必须区分相同模块内的类和不同模块内的类。如果它们在不同的模块中,public则将不允许您继承,因此第三张图像不正确。另外,如果可以看到任何类,都可以随时对其进行扩展。当时,解释扩展的可视性不是一个好主意。
苏珊(Sulthan)

确实,我应该提一下,我的图仅适用于同一模块,因此我只希望用户快速了解到的第三个图像fileprivate仅适用于同一文件。
Stephen Chen

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

6

在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在子类中可访问。

在此处输入图片说明


5

尽管@MartinR和@StephenChen的答案很完美,但是Swift 4有所改变。

私人的现在被认为是私人在其声明也为其扩展一个类。

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


5

已为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均不可访问。


4

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

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

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

情况1:如果在类中将属性或函数声明为私有,那么默认情况下,作用域是该类。 情况2:如果私有实例是在函数体中声明的,则实例的范围仅限于函数体。


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

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

最亲切的问候。


3

这是swift 4的解释。对于swift 3,区别是私有的。swift 3 private无法通过其扩展名访问,只有Class A本身可以访问。

在此处输入图片说明 在迅速4之后,fileprivate变得有点多余,因为人通常不会在同一文件中定义子类。在大多数情况下,私有就足够了。


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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.