Come definire la costante statica in una classe in swift


105

Ho queste definizioni nella mia funzione che funzionano

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

Ma se sposto "testStr" e "testStrLen" a livello di classe, non verrà compilato. Ha detto che "MyClass.Type non ha un membro denominato" testStr ".

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

    func myFunc() {

    }
}

Come posso risolvere questo problema? Non voglio pagare la penalità per aver contato ogni volta un "test" costante.

In base alla mia comprensione dei commenti di seguito, devo farlo:

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

    func myFunc() {

    }
}

C'è un modo in cui non ho bisogno di digitare / inserire due volte "test"? Grazie.


3
possibile duplicato di ViewControl.Type non ha un membro denominato (Il valore iniziale di una proprietà non può dipendere da un'altra proprietà.)
Martin R

1
possibile duplicato di Cambia X e Y in un CGRectMake (con una bella soluzione usando una proprietà pigra)
Martin R

"C'è un modo in cui non ho bisogno di digitare / inserire" test "due volte?" - Sì. Spostare l'inizializzazione di testStrLen in un metodo init (come suggerito in una risposta al primo possibile duplicato), o utilizzare un'inizializzazione pigra (come suggerito in una risposta al secondo possibile duplicato).
Martin R

Risposte:


177

Forse un simpatico idioma per dichiarare le costanti per una classe in Swift è usare semplicemente una struttura chiamata MyClassConstants come la seguente.

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

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

In questo modo le tue costanti saranno definite nell'ambito di un costrutto dichiarato invece di fluttuare globalmente.

Aggiornare

Ho aggiunto una costante di matrice statica, in risposta a un commento che chiede informazioni sull'inizializzazione di matrice statica. Vedere Array Literals in "The Swift Programming Language".

Si noti che sia i valori letterali stringa che la costante stringa possono essere utilizzati per inizializzare l'array. Tuttavia, poiché il tipo di matrice è noto, la costante intera testStrLengthnon può essere utilizzata nell'inizializzatore di matrice.


2
Non potresti invece dichiarare le costanti come private statiche? Allora non sarebbero più globali?
sethfri

3
batte usando .rawValue mentre stavo usando enum
DogCoffee

1
Questa non sarà la soluzione migliore se il codice deve essere utilizzato anche da Objective C, poiché le strutture Swift non sono tradotte in Objective C
mbpro

1
Qual è la differenza tra la dichiarazione di staticcostanti in Structe in Classes?
Jauzee

1
@YOUNG Swift 2.2 Le enumerazioni potrebbero funzionare, ma generalmente le enumerazioni hanno un'associazione semantica più forte rispetto al semplice raggruppamento di costanti in generale. Nel collegamento, le enumerazioni Swift presentano sia valori associati che valori grezzi. È possibile utilizzare valori grezzi, ma la sintassi è MyClassConstants.testStr.rawValueaccedere al valore, che non è sintatticamente amichevole come solo MyClassConstants.testStr.
Martin Woolstenhulme

72

Aggiunta alla risposta di @Martin ...

Se qualcuno ha intenzione di mantenere un file costante a livello di applicazione, è possibile raggruppare la costante in base al tipo o alla natura

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

Chiamata: Constants.MixpanelConstants.activeScreen

AGGIORNAMENTO 5/5/2019 (un po 'fuori tema ma 🤷🏽‍♂️)

Dopo aver letto alcune linee guida sul codice e dalle esperienze personali, sembra che le strutture non siano l'approccio migliore per memorizzare le costanti globali per un paio di ragioni. Soprattutto il codice precedente non impedisce l'inizializzazione della struttura. Possiamo ottenerlo aggiungendo del codice boilerplate ma esiste un approccio migliore

ENUMS

Lo stesso può essere ottenuto utilizzando un enum con una rappresentazione più sicura e chiara

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

print(Constants.MixpanelConstants.activeScreen.rawValue)

2
Grazie. Mi piace, fornisce un modo elegante di gestire le costanti tramite struct.
Abhijeet,

1
Con più esempi ho aggiunto un approccio migliore qui
Anish Parajuli 웃

15

Se capisco correttamente la tua domanda, ti stai chiedendo come puoi creare costanti a livello di classe (statiche - nel gergo C ++) in modo tale da non a) replicare l'overhead in ogni istanza, eb devi ricalcolare ciò che è altrimenti costante.

Il linguaggio si è evoluto - come ogni lettore sa, ma mentre provo questo in Xcode 6.3.1, la soluzione è:

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

Non so se lo static è strettamente necessario in quanto il compilatore aggiunge sicuramente solo una voce per variabile const nella sezione statica del binario, ma influisce sulla sintassi e sull'accesso. Utilizzando statico, è possibile fare riferimento ad esso, anche quando non si dispone di un caso: MyClass.testStrLen.


11

Se desideri effettivamente una proprietà statica della tua classe, questa non è attualmente supportata in Swift. Il consiglio attuale è di aggirare questo problema utilizzando costanti globali:

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

class MyClass {
    func myFunc() {
    }
}

Se si desidera invece che queste siano proprietà di istanza, è possibile utilizzare una proprietà memorizzata in modo pigro per la lunghezza: verrà valutata solo la prima volta che si accede, quindi non la si calcolerà più e più volte.

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

    func myFunc() {
    }
}

1
+1 Peccato che non ci sia ancora modo migliore di queste variabili globali.
Drux

1
So che al momento questo è un vincolo linguistico, ma preferirei evitare di utilizzare le globali a tutti i costi. Penso che l'utilizzo di contenitori struct con qualcosa come ClassNameConstants sarebbe un approccio migliore per ora.
Zorayr

7

Che dire dell'utilizzo di proprietà calcolate?

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

MyClass.myConstant

7

Alcuni potrebbero volere alcune costanti di classe pubbliche mentre altre private.

La parola chiave private può essere utilizzata per limitare l'ambito delle costanti all'interno dello stesso file 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)")
}

}

Altre classi saranno in grado di accedere alle costanti di classe come di seguito

class MyClass2
{

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

} 

2

Provato su Playground


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()

In che modo questo è collegato alla domanda?
Franklin Yu
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.