Comment utiliser les namespaces dans Swift?

La documentation mentionne seulement les types nesteds, mais il n'est pas clair s'ils peuvent être utilisés comme namespaces. Je n'ai trouvé aucune mention explicite des namespaces.

Répondu par SevenTenEleven dans le forum de développement d'Apple :

Les namespaces ne sont pas par file; ils sont par cible (en fonction du paramètre de construction "Product Module Name"). Donc, vous finiriez avec quelque chose comme ceci:

import FrameworkA import FrameworkB FrameworkA.foo() 

Toutes les déclarations Swift sont considérées comme faisant partie d'un module, donc même si vous dites " NSLog " (oui, ça existe toujours) vous obtenez ce que Swift considère comme " Foundation.NSLog ".

Chris Lattner a également tweeté à propos des noms de famille .

L'espacement des noms est implicite dans Swift, toutes les classs (etc) sont implicitement délimitées par le module (cible XCode) dans lequel elles se trouvent. Aucun préfixe de class nécessaire

Semble être très différent de ce que j'ai pensé.

Je dirais que le jeu de mots de Swift est ambitieux; il a reçu beaucoup de publicité qui ne correspond à aucune réalité significative sur le terrain.

Par exemple, les videos WWDC indiquent que si un framework que vous importez a une class MyClass et que votre code a une class MyClass, ces noms ne sont pas en conflit car "name mangling" leur donne des noms internes différents. En réalité, cependant, ils entrent en conflit, dans le sens où votre propre code MyClass gagne, et vous ne pouvez pas spécifier "Non non, je veux dire la class MyClass dans le framework" – en disant TheFramework.MyClass ne fonctionne pas (le compilateur sait ce que vous voulez dire, mais il dit qu'il ne peut pas find une telle class dans le cadre).

Mon expérience est que Swift n'est donc pas le less du monde. En tournant une de mes applications d'Objective-C à Swift, j'ai créé un framework embarqué parce que c'était tellement facile et cool de le faire. L'import du framework, cependant, importe toutes les choses Swift dans le framework – alors hop, encore une fois il n'y a qu'un espace de noms et c'est global. Et il n'y a pas d'en-têtes Swift donc vous ne pouvez cacher aucun nom.

EDIT: Dans la version 3, cette fonctionnalité commence maintenant à être mise en ligne, dans le sens suivant: si votre code principal contient MyClass et votre framework MyFramework contient MyClass, le premier éclipse ce dernier par défaut, mais vous pouvez atteindre celui dans le framework en utilisant la syntaxe MyFramework.MyClass . Ainsi, nous avons en fait les rudiments d'un espace de nom distinct!

EDIT 2: Dans la graine 4, nous avons maintenant des controls d'access! De plus, dans une de mes applications, j'ai un framework embedded et bien sûr, tout était caché par défaut et j'ai dû exposer explicitement tous les bits de l'API publique. C'est une grosse amélioration.

En faisant quelques expérimentations, j'ai fini par créer ces classs "namespaced" dans leurs propres files en étendant le "package" racine. Je ne sais pas si c'est contre les meilleures pratiques ou si cela a des implications dont je suis conscient (?)

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: Ssortingng init(name:Ssortingng) { self.name = name } } } 

PackageTwoClass.swift

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

Modifier:

Je viens de découvrir que la création de "sous-packages" dans le code ci-dessus ne fonctionnera pas si vous utilisez des files séparés. Peut-être que quelqu'un peut suggérer pourquoi ce serait le cas?

Ajouter les files suivants à ce qui précède:

PackageOneSubPackage.swift

 import Foundation extension PackageOne { struct SubPackage { } } 

PackageOneSubPackageClass.swift

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

Son lancer une erreur de compilation: 'SubPackage' n'est pas un type de membre 'PackageOne'

Si je déplace le code de PackageOneSubPackageClass.swift vers PackageOneSubPackage.swift cela fonctionne. N'importe qui?

Édition 2:

Fiddling autour avec ce encore et découvert (dans Xcode 6.1 beta 2) qu'en définissant les packages dans un file, ils peuvent être étendus dans des files distincts:

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

Voici mes files dans un sens: https://gist.github.com/mikajauhonen/d4b3e517122ad6a132b8

Je crois que cela est réalisé en utilisant:

 struct Foo { class Bar { } } 

Ensuite, il peut être consulté en utilisant:

 var dds = Foo.Bar(); 

Swift utilise des modules comme dans python (voir ici et ici ) et comme Kevin Kévin a suggéré que vous pouvez aussi utiliser les types nesteds comme namespaces.

Et pour étendre la réponse de @Daniel A. White, à la WWDC, ils parlaient des modules de swift.

Aussi ici est expliqué:

Les types inférés rendent le code plus propre et less sujet aux erreurs, tandis que les modules éliminent les en-têtes et fournissent des namespaces.

Au cas où quelqu'un serait curieux, en date du 10 juin 2014, il s'agit d'un bug connu dans Swift:

De SevenTenEleven

"Bug connu, désolé! Rdar: // problem / 17127940 Les types de Swift qualifiés par leur nom de module ne fonctionnent pas."

  • Les namespaces sont utiles lorsque vous devez définir une class avec le même nom que la class dans un cadre existant.

  • Supposons que votre application porte le nom MyApp et que vous deviez déclarer votre UICollectionViewController personnalisé.

Vous n'avez pas besoin de préfixer et de sous-classr comme ceci:

 class MAUICollectionViewController: UICollectionViewController {} 

Fais-le comme ça:

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

Pourquoi? . Parce que ce que vous avez déclaré est déclaré dans le module actuel , qui est votre cible actuelle . Et UICollectionViewController de UIKit est déclaré dans le module UIKit .

Comment l'utiliser dans le module actuel?

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

Comment les distinguer d'un autre module?

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

Vous pouvez utiliser l' extension pour utiliser l'approche de struct mentionnée pour l'espace de noms sans avoir à indenter tout votre code vers la droite. Je me suis un peu amusé avec cela et je ne suis pas sûr d'aller aussi loin que de créer des namespaces Controllers et Views comme dans l'exemple ci-dessous, mais cela illustre bien le path à parcourir:

Profiles.swift :

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

Profils / 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 } } 

Profils / Vues / Edit.swift

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

Je n'ai pas utilisé cela dans une application car je n'ai pas encore eu besoin de ce niveau de séparation, mais je pense que c'est une idée intéressante. Cela supprime le besoin de suffixes de classs pairs tels que le suffixe omniprésent de ViewController * qui est fastidieusement long.

Cependant, il ne raccourcit rien quand il est référencé comme dans les parameters de la méthode comme ceci:

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