O que é um bom exemplo para diferenciar entre fileprivate e private no Swift3


142

Este artigo foi útil para entender os novos especificadores de acesso em Swift 3. Também fornece alguns exemplos de diferentes usos de fileprivatee private.

Minha pergunta é - não está usando fileprivateuma função que será usada apenas neste arquivo o mesmo que usar private?

Respostas:


282

fileprivateagora é o que privatecostumava ser nas versões anteriores do Swift: acessíveis a partir do mesmo arquivo de origem. Uma declaração marcada como privateagora só pode ser acessada dentro do escopo lexical em que está declarada. Portanto, privateé mais restritiva que fileprivate.

A partir do Swift 4, as declarações privadas dentro de um tipo são acessíveis a extensões do mesmo tipo se a extensão estiver definida no mesmo arquivo de origem.

Exemplo (tudo em um arquivo de origem):

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()
  • O foométodo privado é acessível apenas dentro do escopo da class A { ... }definição. Nem sequer é acessível a partir de uma extensão para o tipo (no Swift 3, consulte a segunda nota abaixo para alterações no Swift 4).

  • O barmétodo file-private é acessível a partir do mesmo arquivo de origem.

Notas:

  1. A proposta SE-0159 - Corrigir níveis de acesso privado sugeriu reverter para a semântica do Swift 2 no Swift 4. Após uma discussão longa e controversa na lista de discussão de evolução rápida, a proposta foi rejeitada .

  2. A proposta SE-0169 - Melhorar a interação entre declarações e extensões privadas sugere tornar as private declarações dentro de um tipo acessíveis a extensões do mesmo tipo se a extensão for definida no mesmo arquivo de origem. Esta proposta foi aceita e implementada no Swift 4.


2
Se você está convertendo código automaticamente a partir Swift 2-3, Xcode vai se transformar privateem fileprivate. No entanto, se você tem o luxo de fazê-lo manualmente, pode se beneficiar de sair privatecomo private... se compilar, tudo de bom.
Dan Rosenstark 14/03

@DanielLarsson: Re suas sugestões de edição: Ambos os comentários se aplicam à foo()chamada.
Martin R

82

Acabei de desenhar um diagrama sobre privado , privado de arquivo , aberto e público

Espero que possa ajudá-lo rapidamente, para obter uma descrição do texto, consulte a resposta de Martin R

[Atualização Swift 4]

insira a descrição da imagem aqui


9
cuidado, fileprivatenão está ligada à extensão, mas para o arquivo (escrevendo uma extensão da classe A em outro arquivo não permitirá o uso de fileprivatemembros)
Vince

1
Isso parece incorreto. Você está perdendo o ponto principal. Você precisa diferenciar as classes que estão dentro do mesmo módulo e que estão em módulos diferentes. Se eles estiverem em módulos diferentes, publicnão permitirá que você herde, portanto, a terceira imagem está incorreta. Além disso, você sempre pode colocar uma extensão para qualquer classe, se puder vê-la. Explicar a visibilidade nas extensões não é uma boa ideia.
Sulthan

Na verdade, devo mencionar que meu diagrama funciona apenas no mesmo módulo, portanto, na terceira imagem, eu só quero que o usuário entenda rapidamente o fileprivate só funciona no mesmo arquivo.
Stephen Chen

6

Uma regra prática é que você use private para variáveis, constantes, estruturas internas e classes que são usadas apenas dentro da declaração de sua classe / estrutura. Você usa fileprivate para itens que são usados ​​dentro de suas extensões no mesmo arquivo que sua classe / estrutura, mas fora de seus chavetas de definição (por exemplo, seu escopo lexical).

    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

No Swift 4.0, o Private agora está acessível em extensão, mas dentro do mesmo arquivo. Se você declarar / definir a extensão em outro arquivo, sua variável privada não estará acessível à sua extensão **

Arquivo Privado
O acesso privado a arquivos restringe o uso de uma entidade ao seu próprio arquivo de origem definidor. Use o acesso privado a arquivos para ocultar os detalhes de implementação de uma parte específica da funcionalidade quando esses detalhes forem usados ​​em um arquivo inteiro.
Sintaxe: fileprivate <var type> <variable name>
Exemplo: fileprivate class SomeFilePrivateClass {}


Privado
O acesso privado restringe o uso de uma entidade à declaração anexa e às extensões dessa declaração que estão no mesmo arquivo . Use o acesso privado para ocultar os detalhes de implementação de uma parte específica da funcionalidade quando esses detalhes forem usados ​​apenas em uma única declaração.
Sintaxe: private <var type> <variable name>
Exemplo: private class SomePrivateClass {}


Aqui estão mais detalhes sobre todos os níveis de acesso: Swift - Níveis de acesso

Veja estas imagens:
File: ViewController.swift
Aqui, a extensão e o controlador de exibição estão no mesmo arquivo, portanto, a variável privada pode testPrivateAccessLevelser acessada na extensão

insira a descrição da imagem aqui


Arquivo: TestFile.swift
Aqui, a extensão e o controlador de exibição estão em arquivos diferentes, portanto, a variável privada testPrivateAccessLevelnão está acessível na extensão.

insira a descrição da imagem aqui

insira a descrição da imagem aqui


Aqui a classe ViewController2é uma subclasse de ViewControllere ambos estão no mesmo arquivo. Aqui, a variável privada testPrivateAccessLevelnão está acessível na subclasse, mas o fileprivate está acessível na subclasse.

insira a descrição da imagem aqui


5

Embora as respostas de @ MartinR e @ StephenChen sejam perfeitas, o Swift 4 muda as coisas um pouco.

Private agora é considerado privado para uma classe na qual é declarado e também para suas extensões.

O FilePrivate é considerado privado nesse arquivo, seja uma classe na qual a variável está definida, sua extensão ou qualquer outra classe definida no mesmo arquivo.


5

Atualizado para o Swift 5

Privado x FilePrivate

Para maior clareza, cole o snippet de código no 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

    }
}

Nota : Fora do arquivo Swift, o private e o fileprivate não são acessíveis.


4

filePrivate - o nível do controlador de acesso está dentro do arquivo.

caso 1 : se criarmos extensão com o mesmo arquivo de classe e tentarmos acessar a função fileprivate ou a propriedade fileprivate em sua extensão - acesso permitido
caso 2 : se criarmos uma extensão de classe em novo arquivo - e agora tentarmos acessar a função fileprivate ou fileprivate propriedade - acesso não permitido

privado - o nível de controle de acesso está no escopo lexical

case 1 : Se propriedade ou função é declarada como privada na classe - então o escopo é por padrão a classe. caso 2 : se uma instância privada é declarada com no corpo da função - o escopo da instância é limitado ao corpo da função.


3

No exemplo a seguir, construções de linguagem modificadas por privatee fileprivateparecem se comportar de forma idêntica:

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

Isso está de acordo com a intuição, eu acho. Mas existe alguma exceção?

Atenciosamente.


3

Esta é a explicação para o swift 4. No swift 3, a diferença é o privado. O swift 3 private não pode ser acessado por sua extensão, apenas a própria classe A pode acessar.

insira a descrição da imagem aqui Após o swift 4, o fileprivate se torna um pouco redundante, porque a pessoa normalmente não define a subclasse no mesmo arquivo. Privado deve ser suficiente para a maioria dos casos.


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

}

Eu gosto disso porque é super simples para ivars.

Tente alterar o arquivo privado para privado (e vice-versa) e veja o que acontece na compilação ...

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.