Cómo definir la constante estática en una clase en swift

105

Tengo estas definiciones en mi función que funcionan

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

Pero si muevo 'testStr' y 'testStrLen' al nivel de clase, no se compilará. Decía 'MyClass.Type no tiene un miembro llamado' testStr '.

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

    func myFunc() {

    }
}

¿Cómo puedo arreglar esto? No quiero pagar la multa por contar len de una 'prueba' constante cada vez.

Según mi comprensión de los comentarios a continuación, necesito hacer esto:

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

    func myFunc() {

    }
}

¿Hay alguna manera de que no necesite escribir / ingresar "prueba" dos veces? Gracias.

n179911
fuente
3
posible duplicado de ViewControl.Type no tiene un miembro nombrado (el valor inicial de una propiedad no puede depender de otra propiedad).
Martin R
1
posible duplicado de Change the X and Y en un CGRectMake (con una buena solución usando una propiedad perezosa)
Martin R
"¿Hay alguna manera de que no necesite escribir / ingresar" prueba "dos veces?" - Si. Mueva la inicialización de testStrLen a un método init (como se sugiere en una respuesta al primer posible duplicado), o use una inicialización diferida (como se sugiere en una respuesta al segundo posible duplicado).
Martin R

Respuestas:

177

Quizás un buen modismo para declarar constantes para una clase en Swift es simplemente usar una estructura llamada MyClassConstants como la siguiente.

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

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

De esta manera, sus constantes tendrán un alcance dentro de una construcción declarada en lugar de flotar globalmente.

Actualizar

He agregado una constante de matriz estática, en respuesta a un comentario que pregunta sobre la inicialización de matriz estática. Consulte Array Literals en "El lenguaje de programación Swift".

Observe que tanto los literales de cadena como la constante de cadena se pueden usar para inicializar la matriz. Sin embargo, dado que se conoce el tipo de matriz, la constante entera testStrLengthno se puede utilizar en el inicializador de matriz.

Martin Woolstenhulme
fuente
2
¿No podría, en cambio, declarar las constantes como privadas estáticas? ¿No dejarían de ser entonces globales?
sethfri
3
supera el uso de .rawValue como estaba usando enum
DogCoffee
1
Esta no será la mejor solución si el código también se va a utilizar desde Objective C, ya que las estructuras Swift no se traducen a Objective C
mbpro
1
¿Cuál es la diferencia entre declarar staticconstantes en Structy en Classes?
Jauzee
1
@YOUNG Swift 2.2 Las enumeraciones podrían funcionar, pero generalmente las enumeraciones tienen una asociación semántica más fuerte que solo agrupar constantes en general. En el enlace, las enumeraciones Swift presentan tanto valores asociados como valores brutos. Puede usar valores sin procesar, pero la sintaxis es MyClassConstants.testStr.rawValuepara acceder al valor, que no es tan amigable sintácticamente como solo MyClassConstants.testStr.
Martin Woolstenhulme
72

Agregando a la respuesta de @ Martin ...

Si alguien planea mantener un archivo constante a nivel de aplicación, puede agrupar la constante según su tipo o naturaleza.

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

Llamada : Constants.MixpanelConstants.activeScreen

ACTUALIZACIÓN 5/5/2019 (un poco fuera de tema pero 🤷🏽‍♂️)

Después de leer algunas pautas de código y de experiencias personales, parece que las estructuras no son el mejor enfoque para almacenar constantes globales por un par de razones. Especialmente el código anterior no evita la inicialización de la estructura. Podemos lograrlo agregando algún código repetitivo, pero hay un enfoque mejor

ENUMS

Lo mismo se puede lograr usando una enumeración con una representación más segura y clara

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

print(Constants.MixpanelConstants.activeScreen.rawValue)
Clemente Prem
fuente
2
Gracias. Me gusta esto, proporciona una forma elegante de administrar constantes a través de struct.
Abhijeet
1
Con más ejemplos, he agregado un enfoque mejor aquí
Anish Parajuli 웃
15

Si entiendo su pregunta correctamente, está preguntando cómo puede crear constantes de nivel de clase (estáticas, en el lenguaje de C ++) de modo que no a) replique la sobrecarga en cada instancia yb tenga que volver a calcular lo que de otro modo es constante.

El lenguaje ha evolucionado, como todos los lectores saben, pero mientras pruebo esto en Xcode 6.3.1, la solución es:

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

No sé si la estática es estrictamente necesaria, ya que el compilador seguramente solo agrega una entrada por variable constante en la sección estática del binario, pero afecta la sintaxis y el acceso. Mediante el uso de estática, puede hacer referencia a ella, incluso cuando usted no tiene una instancia: MyClass.testStrLen.

Chris Conover
fuente
11

Si realmente desea una propiedad estática de su clase, actualmente no es compatible con Swift. El consejo actual es solucionarlo mediante el uso de constantes globales:

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

class MyClass {
    func myFunc() {
    }
}

Si desea que sean propiedades de instancia, puede usar una propiedad almacenada diferida para la longitud; solo se evaluará la primera vez que se acceda a ella, por lo que no la calculará una y otra vez.

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

    func myFunc() {
    }
}
Nate Cook
fuente
1
+1 Lástima que todavía no parezca mejor manera que estas variables globales.
Drux
1
Sé que esto es una restricción de idioma en este momento, pero prefiero evitar el uso de globales a toda costa. Creo que usar contenedores de estructura con algo como ClassNameConstants sería un mejor enfoque por ahora.
Zorayr
7

¿Qué pasa con el uso de propiedades calculadas?

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

MyClass.myConstant
Emin Bugra Saral
fuente
7

Algunos pueden querer ciertas constantes de clase públicas mientras que otras son privadas.

La palabra clave privada se puede utilizar para limitar el alcance de las constantes dentro del mismo archivo rápido.

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

}

Otras clases podrán acceder a sus constantes de clase como se muestra a continuación

class MyClass2
{

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

} 
ChinLoong
fuente
2

Probé en el patio de recreo


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
fuente
¿Cómo se relaciona esto con la pregunta?
Franklin Yu