¿Funciones / variables estáticas vs de clase en clases Swift?

416

El siguiente código se compila en Swift 1.2:

class myClass {
    static func myMethod1() {
    }
    class func myMethod2() {
    }
    static var myVar1 = ""
}

func doSomething() {
    myClass.myMethod1()
    myClass.myMethod2()
    myClass.myVar1 = "abc"
}

¿Cuál es la diferencia entre una función estática y una función de clase ? ¿Cuál debo usar y cuándo?

Si trato de definir otra variable class var myVar2 = "", dice:

Propiedades almacenadas de clase que aún no se admiten en clases; ¿quiso decir 'estático'?

Cuando se admite esta característica, ¿cuál será la diferencia entre una variable estática y una variable de clase (es decir, cuando ambas se definen en una clase)? ¿Cuál debo usar y cuándo?

(Xcode 6.3)

Sensato
fuente

Respuestas:

690

staticy classambos asocian un método con una clase, en lugar de una instancia de una clase. La diferencia es que las subclases pueden anular los classmétodos; No pueden anular los staticmétodos.

class Las propiedades funcionarán teóricamente de la misma manera (las subclases pueden anularlas), pero aún no son posibles en Swift.

mipadi
fuente
89
Entonces, ¿cuál es la diferencia entre final classfunción y función 'estática' dentro de una clase?
hippo_san
57
@hippo_san, en una clase base los dos son funcionalmente iguales. Sin embargo, finalse puede usar para cortar anulaciones adicionales cuando se usa en una subclase. Los dos tienen su lugar, diría que el uso de statico finalcuando se usa en una función de clase es trivial y depende de su elección de estilo.
Andrew Robinson
8
ah, entonces static func foo(){}en Swift es como public static final foo(){}en Java?
Supuhstar
3
@Supuhstar: Básicamente, sí.
mipadi
2
@mipadi lo entiendo ahora. Para las funciones de clase, podemos reemplazar "estática" con "clase final", pero para las propiedades de una clase, solo podemos tener propiedades estáticas en lugar de propiedades de clase. Entonces la palabra clave "estática" todavía tiene su lugar.
allenlinli
72

Intenté la respuesta y los comentarios de mipadi en el patio de recreo. Y pensé en compartirlo. Aqui tienes. Creo que la respuesta de mipadi debería marcarse como aceptada.

class A{
    class func classFunction(){
    }
    static func staticFunction(){
    }
    class func classFunctionToBeMakeFinalInImmediateSubclass(){
    }
}

class B: A {
    override class func classFunction(){

    }

    //Compile Error. Class method overrides a 'final' class method
    override static func staticFunction(){

    }

    //Lets avoid the function called 'classFunctionToBeMakeFinalInImmediateSubclass' being overriden by subclasses

    /* First way of doing it
    override static func classFunctionToBeMakeFinalInImmediateSubclass(){
    }
    */

    // Second way of doing the same
    override final class func classFunctionToBeMakeFinalInImmediateSubclass(){
    }

    //To use static or final class is choice of style.
    //As mipadi suggests I would use. static at super class. and final class to cut off further overrides by a subclass
}

class C: B{
    //Compile Error. Class method overrides a 'final' class method
    override static func classFunctionToBeMakeFinalInImmediateSubclass(){

    }
}
MadNik
fuente
27

En cuanto a OOP , la respuesta es demasiado simple:

Las subclases pueden anular los métodos de clase , pero no pueden anular los métodos estáticos .

Además de su publicación, si desea declarar una variable de clase (como lo hizo class var myVar2 = ""), debe hacerlo de la siguiente manera:

class var myVar2: String {
    return "whatever you want"
}
eMdOS
fuente
23

También tuve esta confusión en uno de mis proyectos y encontré esta publicación muy útil. Intenté lo mismo en mi patio de recreo y aquí está el resumen. Espero que esto ayude a alguien con propiedades y funciones de tipo almacenados static, final, class, clase anulando vars etc.

class Simple {

    init() {print("init method called in base")}

    class func one() {print("class - one()")}

    class func two() {print("class - two()")}

    static func staticOne() {print("staticOne()")}

    static func staticTwo() {print("staticTwo()")}

    final func yesFinal() {print("yesFinal()")}

    static var myStaticVar = "static var in base"

    //Class stored properties not yet supported in classes; did you mean 'static'?
    class var myClassVar1 = "class var1"

    //This works fine
    class var myClassVar: String {
       return "class var in base"
    }
}

class SubSimple: Simple {
    //Successful override
    override class func one() {
        print("subClass - one()")
    }
    //Successful override
    override class func two () {
        print("subClass - two()")
    }

    //Error: Class method overrides a 'final' class method
    override static func staticOne() {

    }

    //error: Instance method overrides a 'final' instance method
    override final func yesFinal() {

    }

    //Works fine
    override class var myClassVar: String {
        return "class var in subclass"
    }
}

Y aquí están las muestras de prueba:

print(Simple.one())
print(Simple.two())
print(Simple.staticOne())
print(Simple.staticTwo())
print(Simple.yesFinal(Simple()))
print(SubSimple.one())
print(Simple.myStaticVar)
print(Simple.myClassVar)
print(SubSimple.myClassVar)

//Output
class - one()
class - two()
staticOne()
staticTwo()
init method called in base
(Function)
subClass - one()
static var in base
class var in base
class var in subclass
Santosh
fuente
23

Las pruebas en Swift 4 muestran la diferencia de rendimiento en el simulador. Hice una clase con "class func" y struct con "static func" y los ejecuté en la prueba.

la función estática es:

  • 20% más rápido sin la optimización del compilador
  • 38% más rápido cuando la optimización -todo-módulo-optimización está habilitada.

Sin embargo, ejecutar el mismo código en iPhone 7 con iOS 10.3 muestra exactamente el mismo rendimiento.

Aquí hay un proyecto de muestra en Swift 4 para Xcode 9 si desea probarse a sí mismo https://github.com/protyagov/StructVsClassPerformance

Alex Protyagov
fuente
¿Estaba esto en el simulador o dispositivo físico?
mmr118
7

Agregando a las respuestas anteriores, los métodos estáticos son envío estático significa que el compilador sabe qué método se ejecutará en tiempo de ejecución ya que el método estático no se puede anular mientras que el método de clase puede ser un envío dinámico, ya que la subclase puede anularlos.

Ankit Garg
fuente
0

Hay una diferencia más. La clase se puede utilizar para definir propiedades de tipo de tipo calculado solamente. Si necesita una propiedad de tipo almacenado, use static en su lugar.

Clase: - tipo de referencia

struct: - tipo de valor


fuente
0

classse usa dentro Reference Type(clase):

  • propiedad calculada
  • método
  • puede ser anulado por subclase

staticse usa dentro Reference Typey Value Type(clase, enumeración):

  • propiedad calculada y propiedad almacenada
  • método
  • no se puede cambiar por subclase
protocol MyProtocol {
//    class var protocolClassVariable : Int { get }//ERROR: Class properties are only allowed within classes
    static var protocolStaticVariable : Int { get }

//    class func protocolClassFunc()//ERROR: Class methods are only allowed within classes
    static func protocolStaticFunc()
}

struct ValueTypeStruct: MyProtocol {
    //MyProtocol implementation begin
    static var protocolStaticVariable: Int = 1

    static func protocolStaticFunc() {

    }
    //MyProtocol implementation end

//    class var classVariable = "classVariable"//ERROR: Class properties are only allowed within classes
    static var staticVariable = "staticVariable"

//    class func classFunc() {} //ERROR: Class methods are only allowed within classes
    static func staticFunc() {}
}

class ReferenceTypeClass: MyProtocol {
    //MyProtocol implementation begin
    static var protocolStaticVariable: Int = 2

    static func protocolStaticFunc() {

    }
    //MyProtocol implementation end

    var variable = "variable"

//    class var classStoredPropertyVariable = "classVariable"//ERROR: Class stored properties not supported in classes

    class var classComputedPropertyVariable: Int {
        get {
            return 1
        }
    }

    static var staticStoredPropertyVariable = "staticVariable"

    static var staticComputedPropertyVariable: Int {
        get {
            return 1
        }
    }

    class func classFunc() {}
    static func staticFunc() {}
}

final class FinalSubReferenceTypeClass: ReferenceTypeClass {
    override class var classComputedPropertyVariable: Int {
        get {
            return 2
        }
    }
    override class func classFunc() {}
}

//class SubFinalSubReferenceTypeClass: FinalSubReferenceTypeClass {}// ERROR: Inheritance from a final class

[Referencia vs tipo de valor]

yoAlex5
fuente