¿Cómo usar espacios de nombres en Swift?


144

La documentación solo menciona tipos anidados, pero no está claro si se pueden usar como espacios de nombres. No he encontrado ninguna mención explícita de espacios de nombres.


Una búsqueda rápida de Ctrl-F en su iBook no muestra instancias de espacios de nombres ... ¿entonces voy con no?
Justin Niessner

1
No sé por qué esta pregunta está cerrada. Vi espacio de nombres de apertura en el lado izquierdo del icono de Swift, y todavía no puede encontrar ninguna mención de la documentación ...
eonil

No pude encontrar ninguna información sobre esto, Google me llevó a esta pregunta :). Quizás una de las sesiones de la WWDC arroje un poco más de luz sobre esto.
Zyphrax

También estoy esperando que alguien en la WWDC presente una buena explicación.
eonil

La respuesta de Eonil es correcta. Usas módulos en Xcode para separar tus clases.
Zyphrax

Respuestas:


113

Respondido por SevenTenEleven en el foro de desarrollo de Apple :

Los espacios de nombres no son por archivo; son por objetivo (según la configuración de compilación "Nombre del módulo del producto"). Entonces terminarías con algo como esto:

import FrameworkA
import FrameworkB

FrameworkA.foo()

Todas las declaraciones de Swift se consideran parte de algún módulo, por lo que incluso cuando dice " NSLog" (sí, todavía existe), obtiene lo que Swift considera " Foundation.NSLog".

También Chris Lattner tuiteó sobre el espacio de nombres .

El espacio de nombres está implícito en Swift, todas las clases (etc.) están implícitamente definidas por el módulo (destino de Xcode) en el que se encuentran. No se necesitan prefijos de clase

Parece ser muy diferente lo que he estado pensando.


66
Foros de Apple Dev ... ¡He visto tanta planta rodadora que no creerías!
Nicolas Miari

1
El enlace a los foros de desarrollo de Apple ahora está roto, y Apple no ha importado ese hilo al nuevo forums.developer.apple.comsitio de foros, desafortunadamente.
Dai

2
@Dai Parece que es por eso que debemos evitar los foros de Apple para preguntas y respuestas ... Pero a los miembros del equipo de desarrollo central no parece importarles mucho las SO. Que tragedia.
eonil

1
¿Qué quieres decir con planta rodadora?
Alexander Mills

148

Describiría el espacio de nombres de Swift como aspiracional; Se le ha dado mucha publicidad que no corresponde a ninguna realidad significativa sobre el terreno.

Por ejemplo, los videos de WWDC establecen que si un marco que está importando tiene una clase MyClass y su código tiene una clase MyClass, esos nombres no entran en conflicto porque el "cambio de nombre" les da diferentes nombres internos. En realidad, sin embargo, entran en conflicto, en el sentido de que MyClass de su propio código gana, y no puede especificar "No, no, me refiero a MyClass en el marco": decir TheFramework.MyClassque no funciona (el compilador sabe a qué se refiere , pero dice que no puede encontrar esa clase en el marco).

Mi experiencia es que Swift, por lo tanto, no tiene espacio de nombres en lo más mínimo. Al convertir una de mis aplicaciones de Objective-C a Swift, creé un marco incrustado porque era muy fácil y genial de hacer. Sin embargo, al importar el marco, se importan todas las cosas de Swift en el marco, por lo que, una vez más, solo hay un espacio de nombres y es global. Y no hay encabezados Swift, por lo que no puede ocultar ningún nombre.

EDITAR: en la semilla 3, esta característica ahora está comenzando a estar en línea, en el siguiente sentido: si su código principal contiene MyClass y su marco MyFramework contiene MyClass, el primero eclipsa al segundo de forma predeterminada, pero puede alcanzar el que está en el marco mediante el uso de la sintaxis MyFramework.MyClass. ¡Así, de hecho, tenemos los rudimentos de un espacio de nombres distinto!

EDITAR 2: ¡ en la semilla 4, ahora tenemos controles de acceso! Además, en una de mis aplicaciones tengo un marco incrustado y, por supuesto, todo estaba oculto de forma predeterminada y tuve que exponer todos los bits de la API pública explícitamente. Esta es una gran mejora.


44
Gracias por esta respuesta Funciona no solo con Frameworks, sino también con la Biblioteca estándar. Puede "sobrescribir" la matriz, por ejemplo. Entonces "Array" se refiere a su propia clase de Array personalizada, y el Array de la Biblioteca Estándar está disponible como "Swift.Array".
George

3
@George Y de manera similar para NSArray; si lo eclipsas, aún puedes referirte a él como Foundation.NSArray.
mate

1
Entonces, sin tener que clasificar la historia del pensamiento en los espacios de nombres en las versiones beta: ¿dónde está esta respuesta ahora?
Dan Rosenstark

1
@Yar como se indica en las ediciones. El nombre del módulo es un espacio de nombres opcional si hay ambigüedad, y ahora hay privacidad, por lo que los nombres de los módulos están ocultos a menos que se expongan y un nombre se pueda limitar a un archivo.
mate

2
Esto me ha estado molestando durante mucho tiempo, parece que cualquier proyecto Swift no debería usar un prefijo debido a lo que Apple afirma, sin embargo, en este momento todavía se requiere un prefijo, incluso con los modificadores de acceso. Si bien no entrará en conflicto con el paquete o las clases privadas en el marco de Apple, cualquier cosa declarada pública, por ejemplo String, si declara eso nuevamente, o cualquier clase nueva, terminará usando la suya, a menos que, por supuesto, tenga la costumbre de refiriéndose a todas las clases con su espacio de nombres ... no es bueno.
Oscar Gomez

19

Mientras experimentaba un poco con esto, terminé creando estas clases de "espacios de nombres" en sus propios archivos extendiendo el "paquete" raíz. No estoy seguro de si esto va en contra de las mejores prácticas o si tiene alguna implicación que yo sepa (?)

AppDelegate.swift

var n1 = PackageOne.Class(name: "Package 1 class")
var n2 = PackageTwo.Class(name: "Package 2 class")

println("Name 1: \(n1.name)")
println("Name 2: \(n2.name)")

PackageOne.swift

import Foundation

struct PackageOne {
}

PackageTwo.swift

import Foundation

struct PackageTwo {
}

PackageOneClass.swift

extension PackageOne {
    class Class {
        var name: String
        init(name:String) {
            self.name = name
        }
    }
}

PackageTwoClass.swift

extension PackageTwo {
    class Class {
        var name: String
        init(name:String) {
            self.name = name
        }
    }
}

Editar:

Me acabo de enterar de que crear "subpaquetes" en el código anterior no funcionará si se usan archivos separados. ¿Quizás alguien pueda insinuar por qué ese sería el caso?

Agregar los siguientes archivos a lo anterior:

PackageOneSubPackage.swift

import Foundation

extension PackageOne {
    struct SubPackage {
    }
}

PackageOneSubPackageClass.swift

extension PackageOne.SubPackage {
    class Class {
        var name: String
        init(name:String) {
            self.name = name
        }
    }
}

Está arrojando un error de compilación: 'SubPackage' no es un tipo de miembro de 'PackageOne'

Si muevo el código de PackageOneSubPackageClass.swift a PackageOneSubPackage.swift, funciona. ¿Nadie?

Edición 2:

Jugueteando con esto todavía y descubrí (en Xcode 6.1 beta 2) que al definir los paquetes en un archivo se pueden extender en archivos separados:

public struct Package {
  public struct SubPackage {
    public struct SubPackageOne {
    }
    public struct SubPackageTwo {
    }
  }
}

Aquí están mis archivos en un resumen: https://gist.github.com/mikajauhonen/d4b3e517122ad6a132b8


interesante, ¿cómo fue tu prueba?
user2727195

2
No estoy seguro de lo que quieres decir con "prueba", pero seguí adelante y comencé a construir mi aplicación usando la técnica anterior y parece funcionar bien hasta ahora con la advertencia que agregué a mi entrada anterior. Lo estoy haciendo principalmente porque estoy acostumbrado a organizar mi código de esta manera en otros idiomas y agradecería que alguien con más conocimiento pudiera decirme que es una mala idea hasta que vaya demasiado lejos. :)
bWlrYWphdWhvbmVu

1
sigamos adelante ... esto es lo que queremos ... poder tener una misma clase de nombre en dos paquetes diferentes para poder existir y hacer referencia en consecuencia (más importante, archivos diferentes) y si no funciona, todo idea del espacio de nombres es una idea de fracaso ...
user2727195

¿Algún efecto secundario usando "struct" como una forma de hackear espacios de nombres?
Alex Nolasco

No es que me haya encontrado en lo que respecta al rendimiento. Xcode (6.1 GM) en algunos casos raros se queja de tipos no existentes, pero creo que este podría ser el caso cuando no se estructura un código como este también. Recientemente resolví un problema agregando todos los archivos a mi Test-target que no tiene ningún sentido pero resolvió el problema. :)
bWlrYWphdWhvbmVu

12

Creo que esto se logra usando:

struct Foo
{
    class Bar
    {
    }
}

Entonces se puede acceder usando:

var dds = Foo.Bar();

1
Todavía no estoy tan contento con la forma en que se hacen los espacios de nombres ... ¿qué pasa si tengo diez clases diferentes en un espacio de nombres, y además prefiero mantener las clases en sus archivos individuales, no quiero inflar una? file / struct con todas las clases, cualquier sugerencia de Kevin.
user2727195

2
Me pregunto por qué no pensaron incluir paquetes, eso es lo que necesitamos, no espacios de nombres, me refiero a mirar otros lenguajes de alto nivel como Java, C #, ActionScript, todos tienen paquetes, los espacios de nombres en este contexto no son nada diferentes de usar NS u otros prefijos para sus clases de proyecto
usuario2727195

1
No puedo evitar preguntarme si el uso de estructuras como una forma de hackear espacios de nombres puede causar problemas desconocidos.
Alex Nolasco

1
Esta es una buena solución para ello. Intenté usar este enfoque, pero tuve que parar de inmediato. Cuando intenté asignar un espacio de nombres a mis clases relacionadas con la vista (digamos un CustomTableViewCell), el autocompletado en el generador de interfaces no lo sugirió. Tendría que copiar y pegar manualmente el nombre de la clase para la vista si hubiera utilizado este enfoque.
ArG

1
Por lo general, usaría un enum, no un struct, por lo que no puede crear una instancia de a Foo.
Kevin

7

Swift usa módulos como Python (ver aquí y aquí ) y como @Kevin Sylvestre sugirió, también puede usar los tipos anidados como espacios de nombres.

Y para extender la respuesta de @Daniel A. White, en WWDC estaban hablando de los módulos rápidamente.

También aquí se explica:

Los tipos inferidos hacen que el código sea más limpio y menos propenso a errores, mientras que los módulos eliminan los encabezados y proporcionan espacios de nombres.


2
Estoy buscando paquetes como construcción como se menciona en su segundo enlace 6.4 Paquetes (Python), los espacios de nombres como tipos anidados no pueden llegar muy lejos, ¿qué pasa si tengo 10 clases diferentes y en diferentes archivos en un espacio de nombres o digamos un ¿¿¿paquete???
user2727195

7
  • Los espacios de nombres son útiles cuando necesita definir una clase con el mismo nombre que la clase en el marco existente.

  • Supongamos que su aplicación tiene MyAppnombre y necesita declarar su costumbre UICollectionViewController.

No necesita prefijos y subclases como este:

class MAUICollectionViewController: UICollectionViewController {}

Hazlo asi:

class UICollectionViewController {} //no error "invalid redeclaration o..."

¿Por qué? . Porque lo que has declarado se declara en el módulo actual , que es tu objetivo actual . Y UICollectionViewControllerdesde UIKitse declara en UIKitmódulo.

¿Cómo usarlo dentro del módulo actual?

var customController = UICollectionViewController() //your custom class
var uikitController = UIKit.UICollectionViewController() //class from UIKit

¿Cómo distinguirlos de otro módulo?

var customController = MyApp.UICollectionViewController() //your custom class
var uikitController = UIKit.UICollectionViewController() //class from UIKit

3

Puede extensionusar el structenfoque de s mencionado para el espacio de nombres sin tener que sangrar todo su código hacia la derecha. He estado jugando con esto un poco y no estoy seguro que me gustaría ir tan lejos como la creación Controllersy Viewsespacios de nombres, como en el siguiente ejemplo, pero ilustra hasta qué punto puede ir:

Profiles.swift :

// Define the namespaces
struct Profiles {
  struct Views {}
  struct ViewControllers {}
}

Perfiles / ViewControllers / Edit.swift

// Define your new class within its namespace
extension Profiles.ViewControllers {
  class Edit: UIViewController {}
}

// Extend your new class to avoid the extra whitespace on the left
extension Profiles.ViewControllers.Edit {
  override func viewDidLoad() {
    // Do some stuff
  }
}

Perfiles / Vistas / Editar.swift

extension Profiles.Views {
  class Edit: UIView {}
}

extension Profiles.Views.Edit {
  override func drawRect(rect: CGRect) {
    // Do some stuff
  }
}

No he usado esto en una aplicación ya que aún no he necesitado este nivel de separación, pero creo que es una idea interesante. Esto elimina la necesidad de sufijos de clase pares, como el sufijo ubicuo * ViewController, que es molestamente largo.

Sin embargo, no acorta nada cuando se hace referencia, como en parámetros de métodos como este:

class MyClass {
  func doSomethingWith(viewController: Profiles.ViewControllers.Edit) {
    // secret sauce
  }
}

2

En caso de que alguien tuviera curiosidad, a partir del 10 de junio de 2014, este es un error conocido en Swift:

De SevenTenEleven

Error conocido, lo siento! Rdar: // problem / 17127940 Los tipos de Swift que califican por su nombre de módulo no funcionan".


según la publicación de @ matt a continuación, este es un error conocido en Swift en este momento.
Adam Venturella

Esto se soluciona ahora en Beta 3 (lanzamiento el 7 de julio de 2014)
Adam Venturella
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.