Как использовать пространства имен в 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
  }
}