Was ist ein gutes Beispiel, um in Swift3 zwischen fileprivate und private zu unterscheiden?

142

Dieser Artikel war hilfreich, um die neuen Zugriffsspezifizierer in zu verstehen Swift 3. Es gibt auch einige Beispiele für verschiedene Verwendungen von fileprivateund private.

Meine Frage ist - ist die Verwendung fileprivateeiner Funktion, die nur in dieser Datei verwendet wird, nicht dieselbe wie die Verwendung private?

Nikita P.
quelle

Antworten:

282

fileprivateist jetzt das, was privatefrüher in früheren Swift-Versionen war: Zugriff über dieselbe Quelldatei. Auf eine als gekennzeichnete Deklaration privatekann nur innerhalb des lexikalischen Bereichs zugegriffen werden, in dem sie deklariert ist. Sie privateist daher restriktiver als fileprivate.

Ab Swift 4 können Erweiterungen desselben Typs auf private Deklarationen innerhalb eines Typs zugreifen, wenn die Erweiterung in derselben Quelldatei definiert ist.

Beispiel (alles in einer Quelldatei):

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()
  • Auf die private fooMethode kann nur im Rahmen der class A { ... }Definition zugegriffen werden. Es ist nicht einmal über eine Erweiterung des Typs zugänglich (in Swift 3 finden Sie Änderungen in Swift 4 im zweiten Hinweis unten).

  • Auf die dateiprivate barMethode kann über dieselbe Quelldatei zugegriffen werden.

Anmerkungen:

  1. Der Vorschlag SE-0159 - Fix Private Access Levels schlug vor, in Swift 4 auf die Swift 2-Semantik zurückzugreifen. Nach einer langen und kontroversen Diskussion über die Mailingliste von swift-evolution wurde der Vorschlag abgelehnt .

  2. Der Vorschlag SE-0169 - Verbesserung der Interaktion zwischen privaten Deklarationen und Erweiterungen schlägt vor, private Deklarationen innerhalb eines Typs für Erweiterungen desselben Typs zugänglich zu machen, wenn die Erweiterung in derselben Quelldatei definiert ist . Dieser Vorschlag wurde in Swift 4 angenommen und umgesetzt.

Martin R.
quelle
2
Wenn Sie Code automatisch von Swift 2 nach 3 konvertieren, wird Xcode privatezu fileprivate. Wenn Sie jedoch den Luxus haben, es von Hand zu tun, können Sie oft davon profitieren, privateals private... wenn es kompiliert wird, alles gut.
Dan Rosenstark
@ DanielLarsson: Bezüglich Ihrer Bearbeitungsvorschläge: Beide Kommentare gelten für den foo()Anruf.
Martin R
82

Ich zeichne nur ein Diagramm über privat , dateiprivat , offen und öffentlich

Ich hoffe, es kann Ihnen schnell helfen. Eine Textbeschreibung finden Sie in der Antwort von Martin R.

[Update Swift 4]

Geben Sie hier die Bildbeschreibung ein

Stephen Chen
quelle
9
Achtung, fileprivateist nicht mit der Erweiterung, sondern mit der Datei verknüpft (das Schreiben einer Erweiterung der Klasse A in eine andere Datei erlaubt nicht die Verwendung von fileprivateMitgliedern)
Vince
1
Das scheint falsch. Ihnen fehlt der entscheidende Punkt. Sie müssen zwischen Klassen unterscheiden, die sich innerhalb desselben Moduls befinden und sich in verschiedenen Modulen befinden. Wenn sie sich in verschiedenen Modulen befinden public, können Sie nicht erben, daher ist das dritte Bild falsch. Sie können jeder Klasse auch jederzeit eine Erweiterung hinzufügen, wenn Sie sie sehen können. Es ist daher keine gute Idee, die Sichtbarkeit von Erweiterungen zu erklären.
Sulthan
In der Tat sollte ich erwähnen, dass mein Diagramm nur auf demselben Modul funktioniert. Daher möchte ich, dass das dritte Bild, das der Benutzer schnell verstehen soll, dass Fileprivate nur auf derselben Datei funktioniert.
Stephen Chen
6

Eine praktische Faustregel ist, dass Sie private für Variablen, Konstanten, innere Strukturen und Klassen verwenden, die nur innerhalb der Deklaration Ihrer Klasse / Struktur verwendet werden. Sie verwenden fileprivate für Dinge, die innerhalb Ihrer Erweiterungen innerhalb derselben Datei wie Ihre Klasse / Struktur verwendet werden, jedoch außerhalb ihrer definierenden geschweiften Klammern (dh ihres lexikalischen Bereichs).

    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
        }
    }
Josh Homann
quelle
6

In Swift 4.0 ist Private jetzt in der Erweiterung, jedoch in derselben Datei, verfügbar. Wenn Sie eine Erweiterung in einer anderen Datei deklarieren / definieren, kann Ihre Erweiterung nicht auf Ihre private Variable zugreifen **

File Private
File-Private Access beschränkt die Verwendung einer Entität auf ihre eigene definierende Quelldatei. Verwenden Sie den dateiprivaten Zugriff, um die Implementierungsdetails einer bestimmten Funktionalität auszublenden, wenn diese Details in einer gesamten Datei verwendet werden.
Syntax: fileprivate <var type> <variable name>
Beispiel: fileprivate class SomeFilePrivateClass {}


Privat
Privater Zugriff beschränkt die Verwendung einer Entität auf die beiliegende Deklaration und auf Erweiterungen dieser Deklaration, die sich in derselben Datei befinden . Verwenden Sie den privaten Zugriff, um die Implementierungsdetails einer bestimmten Funktionalität auszublenden, wenn diese Details nur in einer einzelnen Deklaration verwendet werden.
Syntax: private <var type> <variable name>
Beispiel: private class SomePrivateClass {}


Hier finden Sie weitere Details zu allen Zugriffsebenen: Swift - Zugriffsebenen

Schauen Sie sich diese Bilder an:
Datei: ViewController.swift
Hier befinden sich sowohl die Erweiterung als auch der Ansichtscontroller in derselben Datei, sodass auf private Variablen testPrivateAccessLevelin der Erweiterung zugegriffen werden kann

Geben Sie hier die Bildbeschreibung ein


Datei: TestFile.swift
Hier befinden sich sowohl die Erweiterung als auch der Ansichts-Controller in unterschiedlichen Dateien, sodass auf private Variablen testPrivateAccessLevelin der Erweiterung nicht zugegriffen werden kann .

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein


Hier ist die Klasse ViewController2eine Unterklasse von ViewControllerund beide befinden sich in derselben Datei. Hier ist auf die private Variable testPrivateAccessLevelin der Unterklasse nicht zugegriffen, auf fileprivate jedoch in der Unterklasse.

Geben Sie hier die Bildbeschreibung ein

Krunal
quelle
5

Obwohl die Antwort von @ MartinR und @ StephenChen perfekt ist, ändert Swift 4 die Dinge ein wenig.

Privat wird jetzt als privat für eine Klasse betrachtet, in der es deklariert ist, sowie für seine Erweiterungen.

FilePrivate wird in dieser Datei als privat betrachtet, sei es eine Klasse, in der die Variable definiert ist, ihre Erweiterung oder eine andere Klasse, die in derselben Datei definiert ist.

Nikita P.
quelle
5

Aktualisiert für Swift 5

Private vs FilePrivate

Fügen Sie zur besseren Übersichtlichkeit das Code-Snippet in Playground ein

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

    }
}

Hinweis : Außerhalb der Swift-Datei kann nicht auf private und dateiprivate Dateien zugegriffen werden.

Arpit Jain
quelle
4

filePrivate - Die Zugriffssteuerungsebene befindet sich in der Datei.

Fall 1 : Wenn wir eine Erweiterung mit derselben Klassendatei erstellen und versuchen, auf die Dateiprivatfunktion oder die Dateiprivateigenschaft in ihrer Erweiterung zuzugreifen - Zugriff erlaubt
Fall 2 : Wenn wir eine Klassenerweiterung in einer neuen Datei erstellen - Und jetzt versuchen, auf die Dateiprivatfunktion oder die Dateiprivatfunktion zuzugreifen Eigentum - Zugang nicht erlaubt

Die private Zugriffskontrollebene ist lexikalisch

Fall 1 : Wenn Eigenschaft oder Funktion in der Klasse als privat deklariert ist, ist der Gültigkeitsbereich standardmäßig die Klasse. Fall 2 : Wenn eine private Instanz mit im Funktionskörper deklariert ist, ist der Umfang der Instanz auf den Funktionskörper beschränkt.

Ashish Chhabra
quelle
3

Im folgenden Beispiel werden Sprachkonstrukte geändert privateund fileprivatescheinen sich identisch zu verhalten:

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

Das ist nach Intuition, denke ich. Aber gibt es eine Ausnahme?

Herzliche Grüße.

Tomas Balderas
quelle
3

Dies ist die Erklärung für Swift 4. Für Swift 3 ist der Unterschied der private. Auf swift 3 private kann nicht über seine Erweiterung zugegriffen werden, nur Klasse A selbst kann darauf zugreifen.

Geben Sie hier die Bildbeschreibung ein Nach Swift 4 wird fileprivate etwas redundant, da die Person normalerweise die Unterklasse nicht in derselben Datei definiert. Privat sollte für die meisten Fälle ausreichen.

Weidian Huang
quelle
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()
    }

}

Ich mag das, weil es für Ivare super einfach ist.

Versuchen Sie, fileprivate in private (und umgekehrt) zu ändern, und sehen Sie, was beim Kompilieren passiert ...

CPD
quelle