web-dev-qa-db-ja.com

Swiftで名前空間を使用する方法は?

ドキュメントにはネストされた型のみが記載されていますが、名前空間として使用できるかどうかは明確ではありません。名前空間の明示的な言及は見つかりませんでした。

136
lassej

Apple開発フォーラムSevenTenElevenが回答

名前空間はファイルごとではありません。それらはターゲットごとです(「製品モジュール名」ビルド設定に基づきます)。したがって、次のような結果になります。

import FrameworkA
import FrameworkB

FrameworkA.foo()

すべてのSwift宣言は一部のモジュールの一部とみなされるため、「NSLog」と言っても(はい、まだ存在します)、Swiftが「Foundation.NSLog」と考えるものが得られます。 「。

Chris Lattnerネームスペースについてツイート .

Swiftでは名前空間は暗黙的であり、すべてのクラス(など)は、それらが含まれるモジュール(Xcodeターゲット)によって暗黙的にスコープされます。

私が考えていたものとは非常に異なるようです。

104
Eonil

私は、Swiftのネームスペースを野心的なものとして説明します。地上の意味のある現実に対応していない広告が多く提供されています。

たとえば、WWDCビデオでは、インポートするフレームワークにクラスMyClassがあり、コードにクラスMyClassがある場合、「名前マングリング」が異なる内部名を与えるため、これらの名前は競合しません。ただし、実際には、doは競合します。つまり、独自のコードのMyClassが勝つという意味で、「いいえ、いいえ、私はフレームワークのMyClass」— TheFramework.MyClassが機能しないと言っています(コンパイラはあなたの意味を知っていますが、フレームワークでそのようなクラスを見つけることができないと言います)。

私の経験では、Swiftは少しでも名前空間化されていません。私のアプリの1つをObjective-CからSwiftに変えたときに、組み込みフレームワークを作成しました。ただし、フレームワークをインポートすると、フレームワーク内のすべてのSwiftものがインポートされます。したがって、今でも、名前空間は1つだけでグローバルです。また、Swiftヘッダーがないため、名前を隠すことはできません。

EDIT:シード3では、この機能は次の意味でオンラインになり始めています:メインコードにMyClassが含まれ、フレームワークMyFrameworkにMyClassが含まれる場合、前者はデフォルトで後者を覆い隠しますが、構文MyFramework.MyClassを使用して、フレームワーク内の1つに到達できます。したがって、実際には別個の名前空間の基礎があります!

編集2:シード4では、アクセス制御ができました!さらに、私のアプリの1つには、組み込みのフレームワークがあり、確かに、デフォルトではすべてが隠されていたため、パブリックAPIのすべてのビットを明示的に公開する必要がありました。これは大きな改善です。

137
matt

これでいくつかの実験を行っている間、ルート「パッケージ」を拡張することにより、独自のファイルにこれらの「名前空間」クラスを作成することになりました。これがベストプラクティスに反するのか、それとも私が気づいている意味を持っているのかどうかはわかりません(?)

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

編集:

上記のコードで「サブパッケージ」を作成すると、別のファイルを使用すると機能しなくなることがわかりました。たぶん、誰かがそれがどうしてそうなるのかを示唆できるでしょうか?

上記に次のファイルを追加します。

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で)パッケージを1つのファイルで定義することで、それらを別のファイルに拡張できることを発見しました。

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

Gistのファイルは次のとおりです。 https://Gist.github.com/mikajauhonen/d4b3e517122ad6a132b8

18

私はこれを使用して達成されると信じています:

struct Foo
{
    class Bar
    {
    }
}

次に、以下を使用してアクセスできます。

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

Swiftはpython( here および here を参照)によく似たモジュールを使用し、@ Kevin Sylvestreが示唆したように ネストされたタイプ 名前空間として。

そして、@ Daniel A. Whiteからの回答を拡張するために、WWDCではSwiftのモジュールについて話していました。

here についても説明します:

推論された型はコードをクリーンにし、ミスを起こしにくくしますが、モジュールはヘッダーを削除して名前空間を提供します。

7
Ivan Genchev
  • 名前空間は、既存のフレームワークのクラスと同じ名前でクラスを定義する必要がある場合に役立ちます。

  • アプリにMyApp名があり、カスタムUICollectionViewControllerを宣言する必要があるとします。

必要ないこのようにプレフィックスとサブクラスを作成するには:

class MAUICollectionViewController: UICollectionViewController {}

次のようにします:

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

なぜ?。宣言したものはcurrent moduleで宣言されているため、これはcurrent targetです。そして、UICollectionViewControllerからのUIKitUIKitモジュールで宣言されています。

現在のモジュール内での使用方法

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

2014年6月10日の時点で誰もが好奇心が強い場合、これはSwiftの既知のバグです。

SevenTenElevenから

「既知のバグ、ごめんなさい!rdar:// problem/1712794モジュール名でSwiftタイプを修飾しても機能しません。」

2
Adam Venturella

extensionを使用すると、前述のstructsアプローチを使用して、すべてのコードを右にインデントすることなく、ネームスペースを作成できます。私はこれを少しいじっていましたが、以下の例のようにControllersViews名前空間を作成するかどうかはわかりませんが、それがどこまで行くことができるかを示しています:

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

Profiles/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
  }
}
1