¿Cómo usar Namespaces en Swift?

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

Respondido por SevenTenEleven en el foro de desarrollo de Apple :

Los espacios de nombres no son por archivo; son por destino (según la configuración de comstackción “Nombre del módulo de 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 dices ” NSLog ” (sí, todavía existe) NSLog lo que Swift considera como ” Foundation.NSLog “.

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

El espaciado de nombres está implícito en Swift, todas las clases (etc.) tienen el scope implícito del módulo (destino XCode) en el que se encuentran. No se necesitan prefijos de clase

Parece ser muy diferente de lo que he estado pensando.

Yo describiría el espacio de nombres de Swift como algo aspiracional; se le ha dado mucha publicidad que no se corresponde con ninguna realidad significativa sobre el terreno.

Por ejemplo, los videos de WWDC indican que si un framework que está importando tiene una clase MyClass y su código tiene una clase MyClass, esos nombres no entran en conflicto porque “name mangling” les da diferentes nombres internos. En realidad, sin embargo, entran en conflicto, en el sentido de que gana MyClass de tu propio código, y no puedes especificar “No no, me refiero a MyClass en el marco” – diciendo TheFramework.MyClass no funciona (el comstackdor sabe lo que quieres decir, pero dice que no puede encontrar esa clase en el marco).

Mi experiencia es que Swift por lo tanto no tiene el 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 hacerlo. La importación del marco, sin embargo, importa todas las cosas de Swift en el marco, así que, una vez más, solo hay un espacio de nombre y es global. Y no hay encabezados Swift, así que no puedes ocultar ningún nombre.

EDITAR: En la semilla 3, esta característica ahora comienza 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 a este último por defecto, pero puede alcanzar el que está en el marco mediante el uso de la syntax MyFramework.MyClass . ¡De hecho, tenemos los rudimentos de un espacio de nombres distinto!

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

Mientras hacía algo de experimentación con esto, terminé creando estas clases de “espacio 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 de la que no tenga conocimiento (?)

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:

Acabo de descubrir que la creación de “subpaquetes” en el código anterior no funcionará si utiliza archivos separados. Tal vez 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á lanzando un error de comstackción: ‘SubPaquete’ no es un tipo de miembro de ‘PackageOne’

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

Editar 2:

Dando vueltas con esto todavía y descubrió (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 una esencia: https://gist.github.com/mikajauhonen/d4b3e517122ad6a132b8

Creo que esto se logra usando:

 struct Foo { class Bar { } } 

Luego se puede acceder usando:

 var dds = Foo.Bar(); 

Swift usa módulos muy similares a los de Python (ver aquí y aquí ) y como @Kevin Sylvestre sugirió que también puedes usar los tipos nesteds como espacios de nombres.

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

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 encabezados y proporcionan espacios de nombres.

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 No es posible utilizar los tipos Swift que califican por su nombre de módulo”.

  • 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 MyApp nombre de MyApp y necesita declarar su UICollectionViewController personalizado.

No es necesario que prefijas y subclases de esta manera:

 class MAUICollectionViewController: UICollectionViewController {} 

Hazlo asi:

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

¿Por qué? . Porque lo que has declarado está declarado en el módulo actual , que es tu objective actual . Y UICollectionViewController de UIKit se declara en el módulo UIKit .

¿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 

Puede usar la extension para usar el enfoque de la struct mencionada para el espaciado de nombres sin tener que aplicar sangría a todo su código hacia la derecha. He estado jugando con esto un poco y no estoy seguro de haber llegado a crear espacios de nombres de Controllers y Views como en el ejemplo a continuación, pero sí ilustra qué tan lejos puede llegar:

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 porque todavía no he necesitado este nivel de separación, pero creo que es una idea interesante. Esto elimina la necesidad de sufijos de clase par, como el omnipresente * sufijo ViewController, que es molestamente largo.

Sin embargo, no acorta nada cuando se hace referencia a él, como en los parámetros del método como este:

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