Funkcje statyczne a funkcje klasowe / zmienne w klasach Swift?

416

Poniższy kod kompiluje się w Swift 1.2:

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

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

Jaka jest różnica między funkcją statyczną a funkcją klasową ? Którego powinienem użyć i kiedy?

Jeśli spróbuję zdefiniować inną zmienną class var myVar2 = "", powie:

Właściwości przechowywane w klasie nie są jeszcze obsługiwane w klasach; miałeś na myśli „static”?

Kiedy ta funkcja jest obsługiwana, jaka będzie różnica między zmienną statyczną a zmienną klasy (tj. Kiedy obie są zdefiniowane w klasie)? Którego powinienem użyć i kiedy?

(Xcode 6.3)

Rozsądny
źródło
Podobne pytanie tutaj: statyczny vs klasa jako zmienna / metoda klasy (Swift) .
Martin R

Odpowiedzi:

690

statici classoba wiążą metodę z klasą, a nie z instancją klasy. Różnica polega na tym, że podklasy mogą zastępować classmetody; nie mogą zastąpić staticmetod.

class właściwości będą teoretycznie działać w ten sam sposób (podklasy mogą je zastąpić), ale nie są jeszcze możliwe w Swift.

mipadi
źródło
89
Jaka jest zatem różnica między final classfunkcją a funkcją „statyczną” w obrębie klasy?
hippo_san
57
@hippo_san, w klasie bazowej oba są funkcjonalnie takie same. Jednakże, finalmoże być użyty do odcięcia dalszych przesłonięcia podczas stosowania w podklasie. Oba mają swoje miejsce, powiedziałbym, że użycie staticlub finalużycie funkcji klasy jest trywialne i zależy od twojego stylu.
Andrew Robinson
8
ah, więc static func foo(){}w Swift jest jak public static final foo(){}w Javie?
Supuhstar,
3
@Supuhstar: Zasadniczo tak.
mipadi
2
@mipadi Rozumiem teraz. W przypadku funkcji klasy możemy zamienić „statyczny” na „klasę końcową”, ale w przypadku właściwości w klasie możemy mieć tylko właściwości statyczne zamiast właściwości klasy. Słowo kluczowe „statyczny” nadal ma swoje miejsce.
allenlinli
72

Próbowałem odpowiedzi i komentarzy mipadi na placu zabaw. I pomyślałem o udostępnieniu. Proszę bardzo. Myślę, że odpowiedź mipadi powinna zostać oznaczona jako zaakceptowana.

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
źródło
27

W odniesieniu do OOP odpowiedź jest zbyt prosta:

Podklasy mogą zastępować metody klasowe , ale nie mogą zastępować metod statycznych .

Oprócz swojego postu, jeśli chcesz zadeklarować zmienną klasową (tak jak zrobiłeś class var myVar2 = ""), powinieneś to zrobić w następujący sposób:

class var myVar2: String {
    return "whatever you want"
}
eMdOS
źródło
23

Ten zamieszanie dostałem również w jednym z moich projektów i uważam ten post za bardzo pomocny. Próbowałem tego samego na moim placu zabaw, a oto podsumowanie. Nadzieję, że to pomoże ktoś z zapisanymi właściwościami i funkcjami typu static, final, class, przesłanianie klasy 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"
    }
}

A oto próbki testowe:

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
źródło
23

Testy w Swift 4 pokazują różnicę wydajności w symulatorze. Zrobiłem klasę z „klasą func” i struktury z „statyczną func” i przetestowałem je.

funkcja statyczna to:

  • 20% szybszy bez optymalizacji kompilatora
  • O 38% szybszy, gdy włączona jest optymalizacja optymalizacji całego modułu.

Jednak uruchomienie tego samego kodu na iPhonie 7 w systemie iOS 10.3 pokazuje dokładnie taką samą wydajność.

Oto przykładowy projekt w Swift 4 dla Xcode 9, jeśli chcesz się przetestować https://github.com/protyagov/StructVsClassPerformance

Alex Protyagov
źródło
czy to było na symulatorze lub urządzeniu fizycznym?
mmr118
7

Jest jeszcze jedna różnica. classmoże służyć do definiowania właściwości typu tylko typu obliczanego . Jeśli potrzebujesz właściwości typu przechowywanego, użyj staticzamiast tego.

„Definiujesz właściwości typu za pomocą słowa kluczowego static. W przypadku właściwości typu obliczanego dla typów klas możesz zamiast tego użyć słowa kluczowego class, aby umożliwić podklasom zastąpienie implementacji nadklasy.”

Maciek Czarnik
źródło
7

Dodanie do powyższych odpowiedzi metody statyczne są statyczną wysyłką, oznacza to, że kompilator wie, która metoda zostanie wykonana w czasie wykonywania, ponieważ metody statycznej nie można zastąpić, podczas gdy metoda klasy może być dynamiczną wysyłką, ponieważ podklasa może je zastąpić.

Anargit garg
źródło
0

Jest jeszcze jedna różnica. Klasa może być używana do definiowania właściwości typu tylko typu obliczanego. Jeśli potrzebujesz właściwości typu przechowywanego, użyj statycznej.

Klasa: - typ odniesienia

struct: - typ wartości


źródło
0

classjest używany wewnątrz Reference Type(klasa):

  • obliczona własność
  • metoda
  • można zastąpić podklasą

staticjest używany wewnątrz Reference Typei Value Type(klasa, wyliczanie):

  • własność obliczona i przechowywana
  • metoda
  • nie można zmienić podklasą
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

[Odniesienie a typ wartości]

yoAlex5
źródło