Jak zdefiniować stałą statyczną w klasie w języku swift

105

Mam te definicje w mojej funkcji, które działają

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

Ale jeśli przeniosę „testStr” i „testStrLen” na poziom klasy, to się nie skompiluje. Mówi się, że „MyClass.Type nie ma elementu członkowskiego o nazwie„ testStr ”.

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

    func myFunc() {

    }
}

Jak mogę to naprawić? Nie chcę płacić kary za odliczanie za każdym razem len ciągłego „testu”.

Na podstawie mojego zrozumienia poniższych komentarzy muszę to zrobić:

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

    func myFunc() {

    }
}

Czy jest sposób, żebym nie musiał dwukrotnie wpisywać / wpisywać słowa „test”? Dzięki.

n179911
źródło
3
możliwy duplikat ViewControl.Type nie ma elementu członkowskiego o nazwie (początkowa wartość właściwości nie może zależeć od innej właściwości.)
Martin R
1
możliwy duplikat Zmień X i Y w CGRectMake (z ładnym rozwiązaniem wykorzystującym leniwą właściwość)
Martin R
„Czy jest sposób, w jaki nie muszę dwukrotnie wpisywać / wpisywać„ test ”?” - Tak. Przenieś inicjalizację testStrLen do metody init (jak zasugerowano w odpowiedzi na pierwszy możliwy duplikat) lub użyj leniwej inicjalizacji (jak zasugerowano w odpowiedzi na drugi możliwy duplikat).
Martin R

Odpowiedzi:

177

Być może fajnym idiomem do deklarowania stałych dla klasy w Swift jest po prostu użycie struktury o nazwie MyClassConstants, takiej jak poniżej.

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

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

W ten sposób twoje stałe będą objęte zakresem zadeklarowanej konstrukcji zamiast unosić się globalnie.

Aktualizacja

Dodałem statyczną stałą tablicową w odpowiedzi na komentarz z pytaniem o statyczną inicjalizację tablicy. Zobacz Array Literals w „The Swift Programming Language”.

Zwróć uwagę, że do zainicjowania tablicy można użyć zarówno literałów łańcuchowych, jak i stałej ciągu. Jednak ponieważ typ tablicy jest znany, testStrLengthnie można użyć stałej liczby całkowitej w inicjatorze tablicy.

Martin Woolstenhulme
źródło
2
Czy nie mógłbyś zamiast tego po prostu zadeklarować stałych jako statyczne prywatne? Czy wtedy nie przestaliby być globalni?
sethfri
3
bije przy użyciu .rawValue, ponieważ używałem wyliczenia
DogCoffee
1
To nie będzie najlepsze rozwiązanie, jeśli kod ma być również używany z celu C, ponieważ struktury Swift nie są tłumaczone na Objective C
mbpro
1
Jaka jest różnica między deklarowaniem staticstałych w Structi we Class?
Jauzee,
1
@YOUNG Swift 2.2 Wyliczenia mogą działać, ale ogólnie wyliczenia mają silniejsze skojarzenie semantyczne niż tylko ogólne grupowanie stałych. W łączu wyliczenia Swift zawierają zarówno powiązane wartości, jak i wartości surowe. Możesz użyć surowych wartości, ale składnia jest taka, MyClassConstants.testStr.rawValueaby uzyskać dostęp do wartości, która nie jest tak przyjazna składniowo jak zwykła MyClassConstants.testStr.
Martin Woolstenhulme
72

Dodawanie do odpowiedzi @ Martina ...

Jeśli ktoś planuje przechowywanie stałego pliku na poziomie aplikacji, można pogrupować stałą na podstawie ich typu lub charakteru

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

Połączenie : Constants.MixpanelConstants.activeScreen

AKTUALIZACJA 05.05.2019 (trochę poza tematem, ale 🤷🏽‍♂️)

Po przeczytaniu kilku wskazówek dotyczących kodu i osobistych doświadczeń wydaje się, że struktury nie są najlepszym podejściem do przechowywania stałych globalnych z kilku powodów. Zwłaszcza powyższy kod nie zapobiega inicjalizacji struktury. Możemy to osiągnąć, dodając jakiś standardowy kod, ale jest lepsze podejście

ENUMS

To samo można osiągnąć, używając wyliczenia z bezpieczniejszą i bardziej przejrzystą reprezentacją

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

print(Constants.MixpanelConstants.activeScreen.rawValue)
Clement Prem
źródło
2
Dziękuję Ci. Podoba mi się to, zapewnia elegancki sposób zarządzania stałymi poprzez struct.
Abhijeet
1
Z większą liczbą przykładów Dodałem lepsze podejście tutaj
Anish Parajuli 웃
15

Jeśli dobrze rozumiem twoje pytanie, pytasz, jak możesz stworzyć stałe na poziomie klasy (statyczne - w języku C ++) tak, aby a) nie powielać narzutu w każdym przypadku i b musisz ponownie obliczyć to, co w innym przypadku jest stałe.

Język ewoluował - jak każdy czytelnik wie, ale gdy testuję to w Xcode 6.3.1, rozwiązaniem jest:

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

Nie wiem, czy statyczne jest absolutnie konieczne, ponieważ kompilator z pewnością dodaje tylko jeden wpis na zmienną const do sekcji statycznej pliku binarnego, ale ma to wpływ na składnię i dostęp. Za pomocą statycznych, można zwrócić się do niego nawet wtedy, gdy nie masz instancji: MyClass.testStrLen.

Chris Conover
źródło
11

Jeśli faktycznie chcesz mieć statyczną właściwość swojej klasy, nie jest ona obecnie obsługiwana w języku Swift. Obecnie radzimy obejść ten problem za pomocą stałych globalnych:

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

class MyClass {
    func myFunc() {
    }
}

Jeśli zamiast tego chcesz, aby były to właściwości instancji, możesz użyć leniwej przechowywanej właściwości dla długości - zostanie ona oceniona tylko przy pierwszym dostępie, więc nie będziesz jej obliczać w kółko.

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

    func myFunc() {
    }
}
Nate Cook
źródło
1
+1 Szkoda, że ​​nadal wydaje się, że nie ma lepszego sposobu niż te zmienne globalne.
Drux
1
Wiem, że w tej chwili jest to ograniczenie językowe, ale wolałbym za wszelką cenę unikać używania języków globalnych. Myślę, że użycie kontenerów struct z czymś takim jak ClassNameConstants byłoby na razie lepszym podejściem.
Zorayr
7

A co z wykorzystaniem obliczonych właściwości?

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

MyClass.myConstant
Emin Bugra Saral
źródło
7

Niektórzy mogą chcieć, aby niektóre stałe klasy były publiczne, a inne prywatne.

private słowo kluczowe może służyć do ograniczenia zakresu stałych w tym samym pliku 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)")
}

}

Inne klasy będą miały dostęp do stałych klas, jak poniżej

class MyClass2
{

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

} 
ChinLoong
źródło
2

Próbowałem na placu zabaw


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
źródło
Jak to się ma do pytania?
Franklin Yu