В документации упоминаются только вложенные типы, но неясно, могут ли они использоваться как пространства имен. Я не нашел явного упоминания пространств имен.
Как использовать пространства имен в Swift?
Ответ 1
Ответа на этот вопрос SevenTenEleven в форуме Apple dev:
Пространства имен не относятся к каждому файлу; они предназначены для каждой цели (на основе "Настройка модуля продукта" ). Таким образом, вы получите что-то например:
import FrameworkA import FrameworkB FrameworkA.foo()
Все объявления Swift считаются частью некоторый модуль, поэтому даже когда вы говорите "
NSLog
" (да, оно все еще существует) вы получаете то, что Swift считает "Foundation.NSLog
".
Также Крис Лэттнер написал в твиттере об именах.
Помещение имен неявно в Swift, все классы (и т.д.) неявно с областью действия модуля (цель XCode), в которой они находятся. Префикс класса необходимо
Кажется, что я совсем другой, о чем я думал.
Ответ 2
Я бы назвал Swift namespacing как желательный; ему была предоставлена много рекламы, которая не соответствует какой-либо значимой реальности на местах.
Например, в видеороликах WWDC указано, что если в структуре, которую вы импортируете, есть класс MyClass, а ваш код имеет класс MyClass, эти имена не конфликтуют, потому что "name mangling" дает им разные внутренние имена. В действительности, однако, они конфликтуют, в том смысле, что выигрывает ваш собственный код MyClass, и вы не можете указать "Нет, я имею в виду MyClass в рамках" - говоря TheFramework.MyClass
не работает (компилятор знает что вы имеете в виду, но он говорит, что не может найти такой класс в рамках).
Мой опыт заключается в том, что Swift, следовательно, не занимает ни малейшего имени. При повороте одного из моих приложений из Objective-C в Swift я создал встроенную фреймворк, потому что было так легко и круто делать. Импортирование фреймворка, однако, импортирует все вещи Swift в рамки - так что престо, еще раз есть только одно пространство имен и оно глобально. И нет заголовков Swift, поэтому вы не можете скрыть никаких имен.
РЕДАКТИРОВАТЬ: В семени 3 эта функция теперь начинает работать в сети, в следующем смысле: если ваш основной код содержит MyClass, а ваша структура MyFramework содержит MyClass, первая затеняет последнее по умолчанию, но вы можете достичь того, что находится в структуре, используя синтаксис MyFramework.MyClass
. Таким образом, у нас действительно есть зачатки отдельного пространства имен!
РЕДАКТИРОВАТЬ 2: В семени 4 мы теперь имеем контроль доступа! Кроме того, в одном из моих приложений у меня встроенная инфраструктура и, конечно же, все было скрыто по умолчанию, и я должен был явно разоблачить все куски открытого API. Это большое улучшение.
Ответ 3
Проведя некоторые эксперименты с этим, я закончил создание этих классов с именами в своих файлах, расширив корневой пакет. Не уверен, что это против лучших практик, или если у него есть какие-либо последствия, мне известно о (?)
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
}
}
}
Edit:
Просто выяснилось, что создание "подпакетов" в вышеприведенном коде не будет работать, если использовать отдельные файлы. Может быть, кто-то может намекнуть, почему это так?
Добавление следующих файлов к следующему:
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"
Если я переведу код из PackageOneSubPackageClass.swift в PackageOneSubPackage.swift, он работает. Кто-нибудь?
Изменить 2:
Вокруг с этим все еще и выяснилось (в Xcode 6.1 beta 2), что, определяя пакеты в одном файле, они могут быть расширены в отдельных файлах:
public struct Package {
public struct SubPackage {
public struct SubPackageOne {
}
public struct SubPackageTwo {
}
}
}
Вот мои файлы в сущности: https://gist.github.com/mikajauhonen/d4b3e517122ad6a132b8
Ответ 4
Я считаю, что это достигается с помощью:
struct Foo
{
class Bar
{
}
}
Затем его можно получить, используя:
var dds = Foo.Bar();
Ответ 5
Swift использует модули, похожие на python (см. здесь и здесь), а также как @Kevin Sylvestre предложил вы также можете использовать вложенные типы как пространства имен.
И чтобы расширить ответ от @Daniel A. White, в WWDC они говорили о модулях в быстром.
Также объясняется здесь:
Предполагаемые типы делают код более чистым и менее подверженным ошибкам, тогда как модули исключают заголовки и предоставляют пространства имен.
Ответ 6
В случае, если кому-то было любопытно, по состоянию на 10 июня 2014 года это известная ошибка в Swift:
Из SevenTenEleven
"Известная ошибка, извините! rdar://problem/17127940 Квалификационные типы Swift по имени их модулей не работают".
Ответ 7
Пространства имен полезны, когда вам нужно определить класс с тем же именем как класс в существующей структуре.
Предположим, что ваше приложение имеет
MyApp
имя, и вам нужно объявить свой пользовательскийUICollectionViewController
.
Вы не нуждаетесь в префикс и подкласс следующим образом:
class MAUICollectionViewController: UICollectionViewController {}
Сделайте это так:
class UICollectionViewController {} //no error "invalid redeclaration o..."
Почему?. Потому что объявленное вами объявлено в текущем модуле, который является вашей текущей целью. И UICollectionViewController
из UIKit
объявлен в модуле UIKit
.
Как использовать его в текущем модуле?
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
Ответ 8
Вы можете использовать extension
для использования упомянутого подхода struct
для пространства имен без необходимости отступать весь код вправо. Я немного поработал с этим, и я не уверен, что я дошел до создания пространств имен Controllers
и Views
, как в приведенном ниже примере, но он иллюстрирует, как далеко он может идти:
Profiles.swift
// Define the namespaces
struct Profiles {
struct Views {}
struct ViewControllers {}
}
Profiles/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
}
}
Профили /Views/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
}
}