クラスの静的定数をSwiftで定義する方法


105

私の機能にはこれらの定義があり、機能します

class MyClass {
    func myFunc() {
        let testStr = "test"
        let testStrLen = countElements(testStr)
    }
}

しかし、「testStr」と「testStrLen」をクラスレベルに移動すると、コンパイルされません。「MyClass.Typeには、「testStr」という名前のメンバーがありません。

class MyClass {
    let testStr = "test"
    let testStrLen = countElements(testStr)

    func myFunc() {

    }
}

どうすれば修正できますか?一定の「テスト」のlenを毎回カウントすることに対するペナルティを払いたくありません。

以下のコメントに対する私の理解に基づいて、私はこれを行う必要があります:

class MyClass {
    let testStr = "test"
    let testStrLen = countElements("test")

    func myFunc() {

    }
}

「test」を2回入力/入力する必要がない方法はありますか?ありがとう。


3
ViewControl.Typeの重複の可能性があるという名前のメンバーがありません(プロパティの初期値は別のプロパティに依存できません。)
Martin R

1
CGRectMakeのXとY変更の複製の可能性(遅延プロパティを使用した優れたソリューションを使用)
Martin R

「「test」を2回入力/入力する必要がない方法はありますか?」- はい。testStrLenの初期化をinitメソッドに移動するか(最初の可能な重複への回答で提案されているように)、または遅延初期化を使用します(2番目の可能な重複への回答で提案されています)。
マーティンR

回答:


177

おそらく、Swiftでクラスの定数を宣言するための優れたイディオムは、次のようなMyClassConstantsという名前の構造体を使用することです。

struct MyClassConstants{
    static let testStr = "test"
    static let testStrLength = countElements(testStr)

    static let arrayOfTests: [String] = ["foo", "bar", testStr]
}

このようにして、定数はグローバルに浮動するのではなく、宣言された構成内でスコープされます。

更新

静的配列の初期化について尋ねるコメントへの応答として、静的配列定数を追加しました。配列リテラルを参照「Swiftプログラミング言語」のを。

文字列リテラルと文字列定数の両方を使用して配列を初期化できることに注意してください。ただし、配列タイプは既知であるため、整数定数testStrLengthは配列初期化子では使用できません。


2
代わりに、定数を静的プライベートとして宣言できませんか?その後、彼らはもはやグローバルではないでしょうか?
sethfri 2015

3
enumを使用していたときの.rawValueを使用したビート
DogCoffee 2015

1
Swift構造体はObjective Cに変換されないため、Objective Cからコードを使用する場合、これは最善の解決策にはなりません
mbpro

1
どのような宣言の違いstaticの定数StructとでClassES?
Jauzee 2016年

1
@YOUNG Swift 2.2列挙は機能しますが、一般的に列挙列挙定数を単にグループ化するよりも意味論的関連性が強いです。リンクでは、Swift列挙型は関連する値と生の値の両方を備えています。未加工の値を使用することもできますが、構文はMyClassConstants.testStr.rawValue値にアクセスするためのものであり、構文的にはそれほど親切ではありませんMyClassConstants.testStr
Martin Woolstenhulme

72

@Martinの回答に追加しています...

アプリケーションレベルの定数ファイルを保持する予定がある場合は、そのタイプまたは性質に基づいて定数をグループ化できます

struct Constants {
    struct MixpanelConstants {
        static let activeScreen = "Active Screen";
    }
    struct CrashlyticsConstants {
        static let userType = "User Type";
    }
}

電話: Constants.MixpanelConstants.activeScreen

UPDATE 5/5/2019(トピックから少し離れていますが、🤷🏽‍♂️)

いくつかのコードガイドラインと個人的な経験から、構造体はいくつかの理由でグローバル定数を格納するための最良のアプローチではないようです。特に上記のコードは、構造体の初期化を妨げません。ボイラープレートコードを追加することでそれを実現できますが、より良いアプローチがあります

ENUMS

同じことは、より安全で明確な表現を持つ列挙型を使用して達成できます

enum Constants {
    enum MixpanelConstants: String {
        case activeScreen = "Active Screen";
    }
    enum CrashlyticsConstants: String {
        case userType = "User Type";
    }
}

print(Constants.MixpanelConstants.activeScreen.rawValue)

2
ありがとうございました。私はこれが好きで、構造体を通じて定数を管理するエレガントな方法を提供します。
Abhijeet

1
より多くの例を用いて、ここで
Anish Parajuli

15

私があなたの質問を正しく理解している場合、クラスレベルの定数(静的-C ++の用語では)を作成して、a)すべてのインスタンスでオーバーヘッドを複製せず、bが他の定数であるものを再計算する必要がある方法を尋ねています。

言語は進化しています-すべての読者が知っているようですが、これをXcode 6.3.1でテストすると、解決策は次のとおりです。

import Swift

class MyClass {
    static let testStr = "test"
    static let testStrLen = count(testStr)

    init() {
        println("There are \(MyClass.testStrLen) characters in \(MyClass.testStr)")
    }
}

let a = MyClass()

// -> There are 4 characters in test

コンパイラがバイナリの静的セクションにconst変数ごとに1つのエントリのみを確実に追加するため、静的が厳密に必要かどうかはわかりませんが、構文とアクセスに影響します。staticを使用すると、インスタンスがない場合でも参照できます:MyClass.testStrLen


11

実際にクラスの静的プロパティが必要な場合、それは現在Swiftではサポートされていません。現在のアドバイスは、グローバル定数を使用してそれを回避することです:

let testStr = "test"
let testStrLen = countElements(testStr)

class MyClass {
    func myFunc() {
    }
}

これらを代わりにインスタンスプロパティにしたい場合は、長さの遅延格納プロパティを使用できます。これは、最初にアクセスされたときにのみ評価されるため、何度も計算することはありません。

class MyClass {
    let testStr: String = "test"
    lazy var testStrLen: Int = countElements(self.testStr)

    func myFunc() {
    }
}

1
+1残念ながら、これらのグローバル変数よりも良い方法はないようです。
Drux、2014年

1
現時点ではこれが言語の制約であることはわかっていますが、グローバルを使用することは絶対に避けたいと思います。今のところは、ClassNameConstantsのような構造コンテナを使用する方が良いと思います。
Zorayr、2015年

7

計算されたプロパティの使用についてはどうですか?

class MyClass {
  class var myConstant: String { return "What is Love? Baby don't hurt me" }
}

MyClass.myConstant

7

特定のクラス定数をパブリックにしたい場合もあれば、プライベートにしたい場合もあります。

privateキーワードを使用して、同じSwiftファイル内の定数のスコープを制限できます。

class MyClass {

struct Constants {

    static let testStr = "test"
    static let testStrLen = testStr.characters.count

    //testInt will not be accessable by other classes in different swift files
    private static let testInt = 1
}

func ownFunction()
{

    var newInt = Constants.testInt + 1

    print("Print testStr=\(Constants.testStr)")
}

}

他のクラスは以下のようにクラス定数にアクセスできます

class MyClass2
{

func accessOtherConstants()
{
    print("MyClass's testStr=\(MyClass.Constants.testStr)")
}

} 

2

遊び場で試しました


class MyClass {

struct Constants { static let testStr = "test" static let testStrLen = testStr.characters.count //testInt will not be accessable by other classes in different swift files private static let testInt = 1 static func singletonFunction() { //accessable print("Print singletonFunction testInt=\(testInt)") var newInt = testStrLen newInt = newInt + 1 print("Print singletonFunction testStr=\(testStr)") } } func ownFunction() { //not accessable //var newInt1 = Constants.testInt + 1 var newInt2 = Constants.testStrLen newInt2 = newInt2 + 1 print("Print ownFunction testStr=\(Constants.testStr)") print("Print ownFunction newInt2=\(newInt2)") } } let newInt = MyClass.Constants.testStrLen print("Print testStr=\(MyClass.Constants.testStr)") print("Print testInt=\(newInt)") let myClass = MyClass() myClass.ownFunction() MyClass.Constants.singletonFunction()

これは質問とどのように関連していますか?
フランクリン・ユー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.