¿Cuál es un buen ejemplo para diferenciar entre fileprivate y private en Swift3?

142

Este artículo ha sido útil para comprender los nuevos especificadores de acceso en Swift 3. También da algunos ejemplos de diferentes usos de fileprivatey private.

Mi pregunta es: ¿no es lo mismo usar fileprivateuna función que se va a usar en este archivo que usar private?

Nikita P
fuente

Respuestas:

282

fileprivateahora es lo que privatesolía ser en versiones anteriores de Swift: accesible desde el mismo archivo fuente. Una declaración marcada como privateahora solo se puede acceder dentro del ámbito léxico en el que se declara. Por privatelo tanto, es más restrictiva que fileprivate.

A partir de Swift 4, las declaraciones privadas dentro de un tipo son accesibles para extensiones del mismo tipo si la extensión se define en el mismo archivo fuente.

Ejemplo (todo en un archivo fuente):

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()
  • fooSolo se puede acceder al método privado dentro del alcance de la class A { ... }definición. Ni siquiera es accesible desde una extensión al tipo (en Swift 3, consulte la segunda nota a continuación para ver los cambios en Swift 4).

  • Se barpuede acceder al método privado de archivo desde el mismo archivo fuente.

Notas:

  1. La propuesta SE-0159 - Arreglar niveles de acceso privado sugirió volver a la semántica de Swift 2 en Swift 4. Después de una discusión larga y controvertida sobre la lista de correo de evolución rápida, la propuesta fue rechazada .

  2. La propuesta SE-0169 - Mejorar la interacción entre declaraciones y extensiones privadas sugiere hacer que las private declaraciones dentro de un tipo sean accesibles para extensiones del mismo tipo si la extensión se define en el mismo archivo fuente. Esta propuesta fue aceptada e implementada en Swift 4.

Martin R
fuente
2
Si está convirtiendo el código automáticamente de Swift 2 a 3, Xcode se convertirá privateen fileprivate. Sin embargo, si tiene el lujo de hacerlo a mano, a menudo puede beneficiarse de irse privatecomo private... si se compila, todo bien.
Dan Rosenstark
@DanielLarsson: Re sus sugerencias de edición: Ambos comentarios se aplican a la foo()llamada.
Martin R
82

Solo dibujo un diagrama sobre privado , privado de archivos , abierto y público

Espero que pueda ayudarlo rápidamente, para la descripción del texto, consulte la respuesta de Martin R

[Actualizar Swift 4]

ingrese la descripción de la imagen aquí

Stephen Chen
fuente
9
cuidado, fileprivateno está vinculado a la extensión sino al archivo (escribir una extensión de clase A en otro archivo no permitirá el uso de fileprivatemiembros)
Vince
1
Esto parece incorrecto. Te estás perdiendo el punto clave. Debe diferenciar entre clases que están dentro del mismo módulo y que están en módulos diferentes. Si están en módulos diferentes, entonces publicno le permitirá heredar, por lo tanto, la tercera imagen es incorrecta. Además, siempre puede poner una extensión a cualquier clase si puede verla. Explicar la visibilidad en las extensiones no es una muy buena idea entonces.
Sulthan
De hecho, debería mencionar que mi diagrama funciona solo en el mismo módulo, por lo tanto, la tercera imagen solo quiero que el usuario entienda rápidamente fileprivate solo funciona en el mismo archivo.
Stephen Chen
6

Una regla práctica es que use private para variables, constantes, estructuras internas y clases que se usan solo dentro de la declaración de su clase / estructura. Utiliza fileprivate para cosas que se usan dentro de sus extensiones dentro del mismo archivo que su clase / estructura pero fuera de sus llaves definidas (es decir, su alcance léxico).

    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
fuente
6

En Swift 4.0, Private ahora es accesible en extensión pero dentro del mismo archivo. Si declara / define la extensión en otro archivo, entonces su variable privada no será accesible para su extensión **

File Private
File-private access restringe el uso de una entidad a su propio archivo fuente de definición. Use el acceso privado a archivos para ocultar los detalles de implementación de una funcionalidad específica cuando esos detalles se usan dentro de un archivo completo.
Sintaxis: fileprivate <var type> <variable name>
Ejemplo: fileprivate class SomeFilePrivateClass {}


Privado
El acceso privado restringe el uso de una entidad a la declaración adjunta y a las extensiones de esa declaración que están en el mismo archivo . Use el acceso privado para ocultar los detalles de implementación de una pieza específica de funcionalidad cuando esos detalles se usan solo dentro de una sola declaración.
Sintaxis: private <var type> <variable name>
Ejemplo: private class SomePrivateClass {}


Aquí hay más detalles sobre todos los niveles de acceso: Swift - Niveles de acceso

Mire estas imágenes:
Archivo: ViewController.swift
Aquí la extensión y el controlador de vista están en el mismo archivo, por lo tanto, la variable privada testPrivateAccessLeveles accesible en extensión

ingrese la descripción de la imagen aquí


Archivo: TestFile.swift
Aquí la extensión y el controlador de vista están en archivos diferentes, por lo tanto, la variable privada testPrivateAccessLevelno es accesible en extensión.

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí


Aquí la clase ViewController2es una subclase de ViewControllery ambos están en el mismo archivo. Aquí testPrivateAccessLevelno se puede acceder a la variable privada en la Subclase, pero se puede acceder a fileprivate en la subclase.

ingrese la descripción de la imagen aquí

Krunal
fuente
5

Aunque la respuesta de @ MartinR y @ StephenChen es perfecta, Swift 4 cambia un poco las cosas.

Privado ahora se considera privado a una clase en la que se declara y también a sus extensiones.

FilePrivate se considera privado en ese archivo, ya sea una clase en la que se define la variable, su extensión o cualquier otra clase definida en ese mismo archivo.

Nikita P
fuente
5

Actualizado para Swift 5

Privado vs FilePrivate

Para mayor claridad, pegue el fragmento de código en 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 : Fuera del archivo Swift, no se puede acceder a los archivos privados ni a los privados.

Arpit Jain
fuente
4

filePrivate : el nivel de control de acceso está dentro del archivo.

caso 1 : si creamos una extensión con el mismo archivo de clase e intentamos acceder a la función fileprivate o la propiedad fileprivate en su extensión - acceso permitido
caso 2 : si creamos una extensión de clase en un archivo nuevo - Y ahora intentamos acceder a la función fileprivate o fileprivate propiedad - acceso no permitido

privado : el nivel de control de acceso tiene un alcance léxico

caso 1 : Si la propiedad o función se declara como privada en la clase, entonces el alcance es por defecto la clase. caso 2 : si la instancia privada se declara con el cuerpo de la función, el alcance de la instancia se limita al cuerpo de la función.

Ashish Chhabra
fuente
3

En el siguiente ejemplo, las construcciones del lenguaje modificadas por privatey fileprivateparecen comportarse de manera 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))

Esto es de acuerdo con la intuición, supongo. Pero, ¿hay alguna excepción?

Saludos cordiales.

Tomás Balderas
fuente
3

Esta es la explicación de swift 4. Para swift 3, la diferencia es el privado. No se puede acceder a swift 3 private por su extensión, solo la clase A puede acceder.

ingrese la descripción de la imagen aquí Después de swift 4, fileprivate se vuelve un poco redundante, porque la persona normalmente no definirá la subclase en el mismo archivo. Privado debería ser suficiente para la mayoría de los casos.

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

}

Me gusta esto porque es súper simple para ivars.

Intente cambiar fileprivate a privado (y viceversa) y vea qué sucede en la compilación ...

CPD
fuente