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

时间:2016-08-18 20:49:22

标签: swift swift3 private access-control access-specifier

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

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

9 个答案:

答案 0 :(得分:269)

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 :(得分:77)

我只是绘制一张关于私人 fileprivate 开放公开

的图表

希望它可以快速帮助您,文字说明请参考 Martin R 的回答

[更新Swift 4]

enter image description here

答案 2 :(得分:6)

一个实际的经验法则是对变量,常量,内部结构和仅在类/结构声明中使用的类使用private。您可以将fileprivate用于与您的类/结构相同的文件中的扩展内部使用的内容,但在其定义的花括号之外(即它们的词法范围)。

struct Person {
  let firstName: String
  let lastName: String
}

答案 3 :(得分: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可以在扩展名

中访问

enter image description here


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

enter image description here

enter image description here


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

enter image description here

答案 4 :(得分:4)

虽然@ MartinR和@ StephenChen的回答是完美的,但 Swift 4 会改变一些事情。

私有现在被视为对其声明的类及其扩展名的私有。

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

答案 5 :(得分: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))

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

最诚挚的问候。

答案 6 :(得分:2)

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

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

答案 7 :(得分:2)

已为Swift 5更新

私有 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文件之外,私有文件和文件私有文件均无法访问。

答案 8 :(得分: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(反之亦然),看看编译时会发生什么......