Статические и классовые функции / переменные в классах Swift?

416

Следующий код компилируется в Swift 1.2:

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

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

В чем разница между статическим функцией и функцией класса ? Какой я должен использовать и когда?

Если я попытаюсь определить другую переменную class var myVar2 = "" , он говорит:

Свойства классов, которые еще не поддерживаются в классах; Вы имели в виду «статический»?

Когда эта функция поддерживается, какова будет разница между статической переменной и переменной класса (т. Е. Когда они оба определены в классе)? Какой я должен использовать и когда?

(Xcode 6.3)

Senseful
источник

Ответы:

690

staticи classоба ассоциируют метод с классом, а не с экземпляром класса. Разница в том, что подклассы могут переопределять classметоды; они не могут переопределять staticметоды.

class свойства теоретически будут функционировать одинаково (подклассы могут их переопределять), но в Swift это пока невозможно.

mipadi
источник
89
Так в чем же разница между final classфункцией и «статической» функцией в классе?
hippo_san
57
@hippo_san, в базовом классе эти два функционально одинаковы. Тем не менее, finalможет использоваться для отключения дальнейших переопределений при использовании в подклассе. Оба имеют свое место, я бы сказал, использование staticили finalкогда используется в функции класса тривиально и зависит от вашего выбора стиля.
Эндрю Робинсон
8
ах, так static func foo(){}в Swift это как public static final foo(){}в Java?
Supuhstar
3
@Supuhstar: В основном, да.
Мипади
2
@mipadi теперь я понимаю. Для функций класса мы можем заменить «статический» на «конечный класс», но для свойств в классе мы можем иметь только статические свойства вместо свойств класса. Таким образом, ключевое слово "static" все еще имеет свое место.
Алленлинли
72

Я попробовал ответ и комментарии Мипади на детской площадке. И думал поделиться этим. Ну вот. Я думаю, что ответ Мипади должен быть отмечен как принятый.

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
источник
27

Относительно ООП , ответ слишком прост:

Подклассы могут переопределять методы класса , но не могут переопределять статические методы.

В дополнение к вашему сообщению, если вы хотите объявить переменную класса (как вы это сделали class var myVar2 = ""), вы должны сделать это следующим образом:

class var myVar2: String {
    return "whatever you want"
}
eMdOS
источник
23

Я также запутался в одном из моих проектов и нашел этот пост очень полезным. Попробовал то же самое на моей игровой площадке и вот резюме. Надеюсь , что это помогает кто - то с хранящимися свойствами и функциями типа static, final, class, перекрывая класс VARS и т.д.

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

А вот и тестовые образцы:

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
Сантош
источник
23

Тестирование в Swift 4 показывает разницу в производительности симулятора. Я создал класс с "class func" и struct с "static func" и запустил их в тесте.

Статическая функция это:

  • 20% быстрее без оптимизации компилятора
  • На 38% быстрее, когда включена оптимизация -whole-module-оптимизация.

Тем не менее, запуск того же кода на iPhone 7 под iOS 10.3 показывает точно такую ​​же производительность.

Вот пример проекта в Swift 4 для Xcode 9, если вы хотите проверить себя https://github.com/protyagov/StructVsClassPerformance

Алекс Протягов
источник
это было на симуляторе или физическом устройстве?
mmr118
7

Есть еще одно отличие. classможет использоваться для определения свойств типа только для вычисляемого типа . Если вам нужно свойство сохраненного типа, используйте staticвместо этого.

«Вы определяете свойства типов с помощью ключевого слова static. Для вычисляемых свойств типов для типов классов вместо этого можно использовать ключевое слово class, чтобы подклассы могли переопределить реализацию суперкласса».

Maciek Czarnik
источник
7

Добавление к вышеупомянутым ответам статических методов - статическая диспетчеризация - означает, что компилятор знает, какой метод будет выполнен во время выполнения, поскольку статический метод не может быть переопределен, в то время как метод класса может быть динамической диспетчеризацией, поскольку подкласс может переопределить их.

Анкит Гарг
источник
0

Есть еще одно отличие. Класс может использоваться для определения свойств типа только для вычисляемого типа. Если вам нужно свойство сохраненного типа, используйте static.

Класс: - тип ссылки

структура: - тип значения


источник
0

classиспользуется внутри Reference Type(класс):

  • компьютерная собственность
  • метод
  • может быть переопределено подклассом

staticиспользуется внутри Reference Typeи Value Type(class, enum):

  • вычисленное свойство и сохраненное свойство
  • метод
  • не может быть изменено подклассом
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

[Ссылка против значения типа]

yoAlex5
источник