So definieren Sie schnell eine statische Konstante in einer Klasse

105

Ich habe diese Definition in meiner Funktion, die funktioniert

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

Wenn ich jedoch 'testStr' und 'testStrLen' auf die Klassenebene verschiebe, wird es nicht kompiliert. Es hieß 'MyClass.Type hat kein Mitglied namens' testStr '.

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

    func myFunc() {

    }
}

Wie kann ich das beheben? Ich möchte nicht die Strafe dafür zahlen, dass ich jedes Mal die Länge eines konstanten 'Tests' gezählt habe.

Aufgrund meines Verständnisses der folgenden Kommentare muss ich Folgendes tun:

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

    func myFunc() {

    }
}

Gibt es eine Möglichkeit, "test" nicht zweimal einzugeben / einzugeben? Vielen Dank.

n179911
quelle
3
Mögliches Duplikat von ViewControl.Type hat kein Mitglied mit dem Namen (Der Anfangswert einer Eigenschaft kann nicht von einer anderen Eigenschaft abhängen.)
Martin R
1
Mögliches Duplikat von Ändern Sie das X und Y in einem CGRectMake (mit einer schönen Lösung unter Verwendung einer Lazy-Eigenschaft)
Martin R
"Gibt es eine Möglichkeit," test "nicht zweimal einzugeben / einzugeben?" - Ja. Verschieben Sie die Initialisierung von testStrLen in eine Init-Methode (wie in einer Antwort auf das erste mögliche Duplikat vorgeschlagen) oder verwenden Sie eine verzögerte Initialisierung (wie in einer Antwort auf das zweite mögliche Duplikat vorgeschlagen).
Martin R

Antworten:

177

Vielleicht ist es eine nette Redewendung zum Deklarieren von Konstanten für eine Klasse in Swift, einfach eine Struktur mit dem Namen MyClassConstants wie die folgende zu verwenden.

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

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

Auf diese Weise werden Ihre Konstanten innerhalb eines deklarierten Konstrukts erfasst, anstatt global zu schweben.

Aktualisieren

Ich habe eine statische Array-Konstante hinzugefügt, als Antwort auf einen Kommentar zur Initialisierung des statischen Arrays. Siehe Array-Literale in "The Swift Programming Language".

Beachten Sie, dass sowohl String-Literale als auch die String-Konstante zum Initialisieren des Arrays verwendet werden können. Da jedoch der Array-Typ bekannt ist, kann die Ganzzahlkonstante testStrLengthim Array-Initialisierer nicht verwendet werden.

Martin Woolstenhulme
quelle
2
Könnten Sie stattdessen nicht einfach die Konstanten als statisch privat deklarieren? Wären sie dann nicht mehr global?
Sethfri
3
schlägt mit .rawValue, als ich enum benutzte
DogCoffee
1
Dies ist nicht die beste Lösung, wenn der Code auch aus Ziel C verwendet werden soll, da Swift-Strukturen nicht um
22:40
1
Was ist der Unterschied zwischen der Deklaration von staticKonstanten in Structund in Classes?
Jauzee
1
@YOUNG Swift 2.2 Aufzählungen könnten funktionieren, aber im Allgemeinen haben Aufzählungen eine stärkere semantische Assoziation als nur das Gruppieren von Konstanten im Allgemeinen. In dem Link enthalten Swift-Enums sowohl zugeordnete Werte als auch Rohwerte. Sie könnten Rohwerte verwenden, aber die Syntax besteht darin MyClassConstants.testStr.rawValue, auf den Wert zuzugreifen, der nicht so syntaktisch freundlich ist wie nur MyClassConstants.testStr.
Martin Woolstenhulme
72

Hinzufügen zu @ Martins Antwort ...

Wenn jemand plant, eine konstante Datei auf Anwendungsebene beizubehalten, können Sie die Konstante nach Typ oder Art gruppieren

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

Anruf : Constants.MixpanelConstants.activeScreen

UPDATE 05.05.2019 (ein bisschen vom Thema ab, aber 🤷🏽‍♂️)

Nach dem Lesen einiger Code-Richtlinien und aus persönlichen Erfahrungen scheint es, dass Strukturen aus mehreren Gründen nicht der beste Ansatz zum Speichern globaler Konstanten sind. Insbesondere der obige Code verhindert nicht die Initialisierung der Struktur. Wir können es erreichen, indem wir etwas Boilerplate-Code hinzufügen, aber es gibt einen besseren Ansatz

ENUMS

Dasselbe kann mit einer Aufzählung mit einer sichereren und klareren Darstellung erreicht werden

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

print(Constants.MixpanelConstants.activeScreen.rawValue)
Clement Prem
quelle
2
Danke dir. Ich mag dies, bietet eine elegante Möglichkeit, Konstanten durch struct zu verwalten.
Abhijeet
1
Mit mehr Beispiele einen besseren Ansatz , den ich hinzugefügt haben hier
Anish Parajuli 웃
15

Wenn ich Ihre Frage richtig verstehe, fragen Sie sich, wie Sie Konstanten auf Klassenebene (statisch - im C ++ - Sprachgebrauch) so erstellen können, dass Sie nicht a) den Overhead in jedem Fall replizieren und b neu berechnen müssen, was sonst konstant ist.

Die Sprache hat sich weiterentwickelt - wie jeder Leser weiß, aber wenn ich dies in Xcode 6.3.1 teste, lautet die Lösung:

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

Ich weiß nicht, ob die Statik unbedingt erforderlich ist, da der Compiler dem statischen Abschnitt der Binärdatei sicherlich nur einen Eintrag pro const-Variable hinzufügt, dies wirkt sich jedoch auf die Syntax und den Zugriff aus. Mit static können Sie auch dann darauf verweisen, wenn Sie keine Instanz haben : MyClass.testStrLen.

Chris Conover
quelle
11

Wenn Sie tatsächlich eine statische Eigenschaft Ihrer Klasse wünschen, wird diese derzeit in Swift nicht unterstützt. Der aktuelle Rat lautet, dies mithilfe globaler Konstanten zu umgehen:

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

class MyClass {
    func myFunc() {
    }
}

Wenn Sie möchten, dass dies stattdessen Instanzeigenschaften sind, können Sie eine verzögert gespeicherte Eigenschaft für die Länge verwenden. Sie wird nur beim ersten Zugriff ausgewertet, sodass Sie sie nicht immer wieder berechnen.

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

    func myFunc() {
    }
}
Nate Cook
quelle
1
+1 Schade, dass es immer noch keinen besseren Weg gibt als diese globalen Variablen.
Drux
1
Ich weiß, dass dies im Moment eine sprachliche Einschränkung ist, aber ich würde es lieber vermeiden, Globals um jeden Preis zu verwenden. Ich denke, die Verwendung von Strukturcontainern mit ClassNameConstants wäre vorerst ein besserer Ansatz.
Zorayr
7

Was ist mit berechneten Eigenschaften?

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

MyClass.myConstant
Emin Bugra Saral
quelle
7

Einige möchten möglicherweise bestimmte Klassenkonstanten öffentlich, andere privat.

Das private Schlüsselwort kann verwendet werden, um den Umfang der Konstanten in derselben schnellen Datei zu begrenzen.

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

}

Andere Klassen können wie unten beschrieben auf Ihre Klassenkonstanten zugreifen

class MyClass2
{

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

} 
ChinLoong
quelle
2

Versucht auf Spielplatz


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()
Kevin6
quelle
Wie hängt das mit der Frage zusammen?
Franklin Yu