如何在Swift中使用命名空间?

文档只提到了嵌套types,但不清楚它们是否可以用作名称空间。 我还没有发现任何明确提及的命名空间。

在Apple开发论坛中由SevenTenEleven回答:

命名空间不是每个文件; 他们是每个目标(根据“产品模块名称”版本设置)。 所以你最终会得到这样的东西:

import FrameworkA import FrameworkB FrameworkA.foo() 

所有的Swift声明都被认为是某个模块的一部分,所以即使你说“ NSLog ”(是的,它仍然存在),你会得到Swift认为的“ Foundation.NSLog ”。

另外Chris Lattner在 Twitter上发布了关于命名空间的推文 。

命名空间在Swift中是隐含的,所有的类(等)都被它们所在的模块(XCode目标)隐式地限定范围。不需要类前缀

似乎和我一直在想的很不一样。

我会把Swift的命名空间描述为理想; 它被给了很多广告,不符合任何有意义的现实。

例如,WWDCvideo指出,如果您要导入的框架具有MyClass类,并且您的代码具有MyClass类,则这些名称不会相互冲突,因为“name mangling”为它们提供了不同的内部名称。 但是,实际上,它们发生冲突,就是说你自己的代码的MyClass会赢,而你不能指定“No no,我的意思是框架中的MyClass” – 说TheFramework.MyClass不起作用(编译器知道你是什​​么意思,但它说在框架中找不到这样的类)。

我的经验是,斯威夫特因此丝毫没有命名空间。 在将我的一个应用程序从Objective-C转换到Swift时,我创build了一个embedded式框架,因为它非常容易和很酷。 但是,导入框架会导入框架中的所有Swift东西 – 所以,再一次,只有一个名称空间,它是全局的。 而且没有Swift头文件,所以你不能隐藏任何名字。

编辑:在种子3,这个function现在开始联机,在以下意义上:如果您的主代码包含MyClass和您的框架MyFramework包含MyClass,前者默认情况下掩盖后者,但你可以达到在框架通过使用语法MyFramework.MyClass 。 因此,我们确实有一个独特的命名空间的雏形!

编辑2:在种子4,我们现在有访问控制! 另外,在我的一个应用程序中,我有一个embedded式框架,当然,默认情况下,所有东西都是隐藏的,我必须明确公开所有的API。 这是一个很大的改进。

在对此进行一些实验的时候,我最终通过扩展根“package”来在自己的文件中创build这些“命名空间”类。 不知道这是否违背最佳实践,或者如果它有我意识到的任何影响(?)

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

编辑:

刚刚发现,在上面的代码中创build“子包”不会工作,如果使用单独的文件。 也许有人可以暗示为什么会这样?

将以下文件添加到上面:

PackageOneSubPackage.swift

 import Foundation extension PackageOne { struct SubPackage { } } 

PackageOneSubPackageClass.swift

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

它抛出一个编译器错误:“SubPackage”不是“PackageOne”的成员types

如果我将代码从PackageOneSubPackageClass.swift移动到PackageOneSubPackage.swift,它就可以工作。 任何人?

编辑2:

摆弄这个仍然发现(在Xcode 6.1testing版2),通过定义在一个文件中的包,他们可以扩展在单独的文件:

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

以下是我的档案: https : //gist.github.com/mikajauhonen/d4b3e517122ad6a132b8

我相信这是通过使用:

 struct Foo { class Bar { } } 

然后可以使用以下方式访问它:

 var dds = Foo.Bar(); 

Swift很像Python中使用模块(参见这里和这里 ),而@Kevin Sylvestrebuild议你也可以使用嵌套types作为名称空间。

为了扩展来自@Daniel A. White的答案,他们在WWDC上迅速地讨论了这些模块。

另外在这里解释:

推断types使代码更清晰,不易出错,而模块消除标题并提供名称空间。

如果有人好奇,截至2014年6月10日,这是Swift中的一个已知错误:

SevenTenEleven

“已知的错误,对不起! rdar://问题/ 17127940通过模块名称来限定 Swifttypes不起作用。”

  • 命名空间在需要在现有框架中定义与类名相同的类时非常有用。

  • 假设您的应用程序具有MyApp名称,并且您需要声明您的自定义UICollectionViewController

不需要这样的前缀和子类:

 class MAUICollectionViewController: UICollectionViewController {} 

像这样做:

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

为什么? 。 因为你声明的是在当前模块中声明的,这是你当前的目标UIKit UICollectionViewControllerUIKit模块中声明。

如何在当前模块中使用它?

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

如何区分他们从另一个模块?

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

你可以使用extension来为命名空间使用上面提到的struct方法,而不必将所有的代码缩进到右边。 我一直在玩弄这一点,我不知道我会尽可能创buildControllersViews命名空间,如下面的例子,但它确实说明了它可以走多远:

Profiles.swift

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

概况/ 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 } } 

概况/浏览/ Edit.swift

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

我没有使用这个应用程序,因为我不需要这种分离的程度,但我认为这是一个有趣的想法。 这消除了甚至类后缀的需要,如无处不在的* ViewController后缀,这是烦人的长。

但是,它在引用的时候并不会缩短任何东西,比如像这样的方法参数:

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