Jaki jest dobry przykład do rozróżnienia między fileprivate i private w Swift3

142

Ten artykuł był pomocny w zrozumieniu nowych specyfikatorów dostępu w Swift 3. Zawiera również przykłady różnych zastosowań fileprivatei private.

Moje pytanie brzmi - czy użycie fileprivatefunkcji, która ma być używana tylko w tym pliku, nie jest tym samym, co użycie private?

Nikita P.
źródło

Odpowiedzi:

282

fileprivatejest teraz tym, co privatebyło we wcześniejszych wersjach Swift: dostępne z tego samego pliku źródłowego. Deklaracja oznaczona jako privatejest teraz dostępna tylko w zakresie leksykalnym, w którym jest zadeklarowana. Więc privatejest bardziej restrykcyjna niż fileprivate.

Począwszy od Swift 4, prywatne deklaracje wewnątrz typu są dostępne dla rozszerzeń tego samego typu, jeśli rozszerzenie jest zdefiniowane w tym samym pliku źródłowym.

Przykład (wszystko w jednym pliku źródłowym):

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()
  • Metoda prywatna foojest dostępna tylko w zakresie class A { ... }definicji. Nie jest nawet dostępny z rozszerzenia do typu (w Swift 3, zobacz drugą uwagę poniżej, aby zapoznać się ze zmianami w Swift 4).

  • Metoda plik-prywatny barjest dostępna z tego samego pliku źródłowego.

Uwagi:

  1. Propozycja SE-0159 - Fix Private Access Levels sugerowała powrót do semantyki Swift 2 w Swift 4. Po długiej i kontrowersyjnej dyskusji na temat listy mailingowej swift-evolution, propozycja została odrzucona .

  2. Propozycja SE-0169 - Poprawa interakcji między prywatnymi deklaracjami i rozszerzeniami sugeruje, aby private deklaracje wewnątrz typu były dostępne dla rozszerzeń tego samego typu, jeśli rozszerzenie jest zdefiniowane w tym samym pliku źródłowym. Ta propozycja została zaakceptowana i wdrożona w Swift 4.

Martin R.
źródło
2
Jeśli automatycznie konwertujesz kod ze Swift 2 na 3, Xcode zmieni się privatew fileprivate. Jeśli jednak masz luksus robienia tego ręcznie, często możesz skorzystać z pozostawienia go privatetak, privatejakby… jeśli się skompiluje, wszystko dobrze.
Dan Rosenstark
@DanielLarsson: Jeśli chodzi o sugestie zmian: oba komentarze odnoszą się do foo()rozmowy.
Martin R
82

Po prostu rysuję diagram dotyczący prywatnego , prywatnego pliku , otwartego i publicznego

Nadzieję, że może szybko pomóc, do opisu tekstowego patrz Martin R odpowiedź „s

[Zaktualizuj Swift 4]

wprowadź opis obrazu tutaj

Stephen Chen
źródło
9
uważaj, fileprivatenie jest powiązany z rozszerzeniem, ale z plikiem (zapisanie rozszerzenia klasy A w innym pliku nie pozwoli na użycie fileprivateczłonków)
Vince
1
Wydaje się to niewłaściwe. Brakuje Ci kluczowego punktu. Musisz rozróżnić klasy znajdujące się w tym samym module i w różnych modułach. Jeśli są w różnych modułach public, nie pozwolą Ci na dziedziczenie, dlatego trzeci obraz jest nieprawidłowy. Możesz też zawsze dodać rozszerzenie do dowolnej klasy, jeśli ją widzisz. Wyjaśnienie widoczności rozszerzeń nie jest więc dobrym pomysłem.
Sulthan
Rzeczywiście, powinienem wspomnieć, że mój diagram działa tylko na tym samym module, dlatego trzeci obraz Chcę tylko, aby użytkownik szybko zrozumiał, że fileprivate działa tylko na tym samym pliku.
Stephen Chen
6

Praktyczna zasada jest taka, że ​​używasz private dla zmiennych, stałych, struktur wewnętrznych i klas, które są używane tylko w deklaracji twojej klasy / struktury. Używasz fileprivate do rzeczy, które są używane wewnątrz twoich rozszerzeń w tym samym pliku co twoja klasa / struktura, ale poza ich definiującymi nawiasami klamrowymi (tj. Ich zakres leksykalny).

    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
źródło
6

W Swift 4.0 prywatna jest teraz dostępna w rozszerzeniu, ale w tym samym pliku. Jeśli zadeklarujesz / zdefiniujesz rozszerzenie w innym pliku, twoja prywatna zmienna nie będzie dostępna dla twojego rozszerzenia **

Plik
prywatny Dostęp prywatny do pliku ogranicza użycie jednostki do jej własnego definiującego pliku źródłowego. Użyj prywatnego dostępu do plików, aby ukryć szczegóły implementacji określonej funkcji, gdy te szczegóły są używane w całym pliku.
Składnia: fileprivate <var type> <variable name>
Przykład: fileprivate class SomeFilePrivateClass {}


Prywatny
Prywatny dostęp ogranicza użycie jednostki do załączonej deklaracji i do rozszerzeń tej deklaracji, które znajdują się w tym samym pliku . Użyj dostępu prywatnego, aby ukryć szczegóły implementacji określonej funkcji, gdy te szczegóły są używane tylko w ramach jednej deklaracji.
Składnia: private <var type> <variable name>
Przykład: private class SomePrivateClass {}


Oto więcej szczegółów na temat wszystkich poziomów dostępu: Swift - poziomy dostępu

Spójrz na te obrazy:
Plik: ViewController.swift
Tutaj rozszerzenie i kontroler widoku znajdują się w tym samym pliku, dlatego zmienna prywatna testPrivateAccessLeveljest dostępna w rozszerzeniu

wprowadź opis obrazu tutaj


Plik: TestFile.swift
Tutaj rozszerzenie i kontroler widoku znajdują się w różnych plikach, dlatego zmienna prywatna testPrivateAccessLevelnie jest dostępna w rozszerzeniu.

wprowadź opis obrazu tutaj

wprowadź opis obrazu tutaj


Tutaj klasa ViewController2jest podklasą ViewControlleri obie znajdują się w tym samym pliku. Tutaj zmienna prywatna testPrivateAccessLevelnie jest dostępna w podklasie, ale fileprivate jest dostępna w podklasie.

wprowadź opis obrazu tutaj

Krunal
źródło
5

Chociaż odpowiedzi @ MartinR i @ StephenChen są doskonałe, Swift 4 trochę zmienia rzeczy.

Prywatny jest teraz traktowany jako prywatny dla klasy, w której jest zadeklarowany, a także dla jego rozszerzeń.

FilePrivate jest uważane za prywatne w tym pliku, niezależnie od tego, czy jest to klasa, w której jest zdefiniowana zmienna, jej rozszerzenie, czy inne klasy zdefiniowane w tym samym pliku.

Nikita P.
źródło
5

Zaktualizowano dla Swift 5

Prywatne a FilePrivate

Dla większej przejrzystości wklej fragment kodu w 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

    }
}

Uwaga : Poza plikiem Swift zarówno private, jak i fileprivate nie są dostępne.

Arpit Jain
źródło
4

filePrivate - poziom kontroli dostępu znajduje się w pliku.

Przypadek 1 : Jeśli tworzymy rozszerzenie z w tym samym pliku klasy i spróbujemy uzyskać dostęp do funkcji fileprivate lub właściwości fileprivate w swoim rozszerzeniu - dostęp dozwolony
Przypadek 2 : Jeśli utworzymy rozszerzenie klasy w nowym pliku - A teraz spróbuj uzyskać dostęp do funkcji fileprivate lub fileprivate właściwość - dostęp niedozwolony

prywatny - poziom kontroli dostępu jest w zakresie leksykalnym

Przypadek 1 : Jeśli właściwość lub funkcja jest zadeklarowana jako prywatna w klasie - wtedy zasięg jest domyślnie klasą. przypadek 2 : jeśli prywatna instancja jest zadeklarowana z treścią funkcji - wtedy zakres instancji jest ograniczony do treści funkcji.

Ashish Chhabra
źródło
3

W poniższym przykładzie konstrukcje językowe zmodyfikowane przez privatei fileprivatewydają się zachowywać identycznie:

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

Chyba wynika to z intuicji. Ale czy jest jakiś wyjątek?

Z wyrazami szacunku.

Tomas Balderas
źródło
3

To jest wyjaśnienie dla swift 4. W przypadku swift 3 różnica jest prywatna. Swift 3 private nie jest dostępny przez jego rozszerzenie, tylko sama klasa A może uzyskać dostęp.

wprowadź opis obrazu tutaj Po Swift 4 fileprivate staje się trochę zbędne, ponieważ osoba normalnie nie definiuje podklasy w tym samym pliku. Prywatny powinien wystarczyć w większości przypadków.

Weidian Huang
źródło
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()
    }

}

Podoba mi się to, ponieważ jest to bardzo proste w przypadku bluszczu.

Spróbuj zmienić fileprivate na private (i odwrotnie) i zobacz, co się stanie podczas kompilacji ...

CPD
źródło