web-dev-qa-db-fra.com

Comment utiliser les espaces de noms dans Swift?

La documentation ne mentionne que les types imbriqués, mais il n'est pas clair s'ils peuvent être utilisés comme espaces de noms. Je n'ai trouvé aucune mention explicite d'espaces de noms.

136
lassej

Répondu par SevenTenEleven dans le forum Apple dev :

Les espaces de noms ne sont pas par fichier; ils sont ciblés (sur la base du paramètre de construction "Product Module Name"). Donc, vous vous retrouveriez avec quelque chose comme ça:

import FrameworkA
import FrameworkB

FrameworkA.foo()

Toutes les déclarations Swift sont considérées comme faisant partie de certains modules. Ainsi, même lorsque vous dites "NSLog" (oui, il existe toujours), vous obtenez ce que Swift pense de comme "Foundation.NSLog".

Aussi Chris Lattner a tweeté à propos de l'espacement des noms .

L'espace de noms est implicite dans Swift, toutes les classes (etc.) sont implicitement délimitées par le module (cible Xcode) dans lequel elles se trouvent. Aucun préfixe de classe n'est nécessaire

Semble être très différent de ce que je pensais.

105
Eonil

Je décrirais le nom de Swift comme une aspiration; On lui a donné beaucoup de publicité qui ne correspond à aucune réalité significative sur le terrain.

Par exemple, les vidéos WWDC indiquent que si une infrastructure que vous importez a une classe MyClass et que votre code a une classe MyClass, ces noms ne sont pas en conflit car "nom mangling" leur donne des noms internes différents. En réalité, cependant, ils sont en conflit , en ce sens que la MyClass de votre propre code l'emporte et que vous ne pouvez pas spécifier "Non, je veux dire le MyClass dans le cadre "- dire TheFramework.MyClass ne fonctionne pas (le compilateur sait ce que vous voulez dire, mais il ne peut pas trouver une telle classe dans le cadre).

Mon expérience est que Swift n'est donc pas le moins du monde espacé. En transformant l'une de mes applications d'Objective-C en Swift, j'ai créé un cadre intégré, car il était si facile et si cool de le faire. L'importation du cadre, cependant, importe tous les éléments Swift du cadre - alors voilà, encore une fois, il n'y a qu'un seul espace de noms et il est global. Et il n'y a pas d'en-tête Swift, vous ne pouvez donc pas cacher de noms.

EDIT: Dans la graine 3, cette fonctionnalité commence maintenant à être mise en ligne, dans le sens suivant: si votre code principal contient MyClass et que votre cadre, MyFramework, contient MyClass, le premier masque plus le dernier par défaut, mais vous peut atteindre celui du framework en utilisant la syntaxe MyFramework.MyClass. Nous avons donc en fait les bases d’un espace de noms distinct!

EDIT 2: Dans la graine 4, nous avons maintenant des contrôles d'accès! De plus, dans l'une de mes applications, j'ai un cadre intégré et, bien entendu, tout était masqué par défaut et je devais exposer explicitement tous les éléments de l'API publique. C'est une grande amélioration.

141
matt

En expérimentant cela, j'ai fini par créer ces classes "namespaced" dans leurs propres fichiers en développant la racine "package". Je ne sais pas si cela va à l’encontre des meilleures pratiques ou si cela a des implications dont je suis au courant (?)

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

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 fichiers séparés. Peut-être que quelqu'un peut dire pourquoi cela serait le cas?

Ajout des fichiers suivants à ce qui précède:

PackageOneSubPackage.Swift

import Foundation

extension PackageOne {
    struct SubPackage {
    }
}

PackageOneSubPackageClass.Swift

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

Son lançant une erreur du compilateur: 'SubPackage' n'est pas un type de membre de 'PackageOne'

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

Éditer 2:

On a bidouillé avec cette photo et on a découvert (dans Xcode 6.1 beta 2) qu'en définissant les paquetages dans un fichier, ils peuvent être étendus dans des fichiers séparés:

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

Voici mes fichiers dans un Gist: https://Gist.github.com/mikajauhonen/d4b3e517122ad6a132b8

18
bWlrYWphdWhvbmVu

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

struct Foo
{
    class Bar
    {
    }
}

Ensuite, vous pouvez y accéder en utilisant:

var dds = Foo.Bar();
12
Kevin Sylvestre

Swift utilise des modules très similaires à python (voir ici et ici ) et, comme @Kevin Sylvestre l’a suggéré, vous pouvez également utiliser les types imbriqués). comme espaces de noms.

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

Aussi ici est expliqué:

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

7
Ivan Genchev
  • Les espaces de noms sont utiles lorsque vous devez définir une classe avec le même nom comme classe dans la structure existante.

  • Supposons que votre application ait le nom MyApp et que vous ayez besoin de déclarer votre personnalisation UICollectionViewController.

Vous n'avez pas besoin préfixer et sous-classer 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 module actuel, qui est votre cible actuelle. Et UICollectionViewController à partir 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

Au cas où quelqu'un serait curieux, à partir du 10 juin 2014, il s'agit d'un bug connu de Swift:

De SevenTenEleven

"Bogue connu, désolé! rdar: // problem/1712794 Qualifier Swift les types par leur nom de module ne fonctionnent pas."

2
Adam Venturella

Vous pouvez utiliser extension pour utiliser la méthode structs mentionnée pour les espaces de noms sans avoir à indenter tout votre code vers la droite. Cela fait un peu que je joue avec cela et je ne suis pas sûr que j'irais jusqu'à créer des espaces de noms Controllers et Views comme dans l'exemple ci-dessous, mais cela montre jusqu'où cela peut aller. :

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 classe, tels que le suffixe ubiquitous * ViewController qui est extrêmement long.

Cependant, cela ne raccourcit rien quand il est référencé, comme dans les paramètres de méthode comme ceci:

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