Swift에서 정적 기능과 클래스 기능의 차이점은 무엇입니까?


334

Swift 라이브러리에서 이러한 정의를 볼 수 있습니다.

extension Bool : BooleanLiteralConvertible {
    static func convertFromBooleanLiteral(value: Bool) -> Bool
}

protocol BooleanLiteralConvertible {
    typealias BooleanLiteralType
    class func convertFromBooleanLiteral(value: BooleanLiteralType) -> Self
}

로 정의 된 멤버 함수 static func와로 정의 된 다른 멤버 함수의 차이점은 무엇입니까 class func? 그것은 단순히 static구조체와 열거의 정적 함수와 class클래스와 프로토콜을위한 것입니까? 알아야 할 다른 차이점이 있습니까? 구문 자체에서 이러한 차이점을 갖는 이유는 무엇입니까?


3
실제로 차이는 없습니다. 그들은 내가 생각하는 구조체에서 클래스 func을 사용할 수 없으므로 정적 func입니다. struct func은 좋은 후보 였을 것입니다. 당신이 나에게 묻는다면 이것은 약간 초초이지만, 글쎄, 그 단어입니다.
truillot de chambrier 제작 :

2
보너스 질문 : 구조체가 class func? 를 정의하는 프로토콜을 준수 할 수 있습니까? 우리가 지금 가지고있는 정보로이 구별은 쓸모없는 것처럼 보이지 않습니까?
Jean-Philippe Pellet

3
그래 넌 할수있어. 이상하지 않습니까?
truillot de chambrier 제작 :

7
압도적 인 차이는 class funcs 를 무시할 수 있다는 것입니다
Fattie

1
고려되어야한다 :error: class methods are only allowed within classes; use 'static' to declare a static method
가브리엘 곤칼베스에게

답변:


238

정적은 구조체와 열거의 정적 함수, 클래스와 프로토콜의 클래스를위한 것입니까?

이것이 주요 차이점입니다. 다른 차이점은 클래스 함수가 ​​동적으로 디스패치되고 서브 클래스로 대체 될 수 있다는 것입니다.

프로토콜은 클래스 키워드를 사용하지만 프로토콜 구현에서 구조체를 배제하지는 않으며 대신 정적을 사용합니다. 프로토콜을 위해 클래스가 선택되었으므로 정적 또는 클래스를 나타내는 세 번째 키워드가 필요하지 않습니다.

이 주제에 관한 Chris Lattner의 글 :

우리는 구문 통합 (예 : "type"을 키워드로 사용)을 고려했지만 실제로는 단순한 것이 아닙니다. 키워드 "class"와 "static"은 친숙하고 유익합니다 (한 번 + 메소드 작동 방식을 이해 한 후). 정적 메소드를 클래스에 추가 할 수있는 기회를 제공합니다. 이 모델의 가장 이상한 점은 프로토콜이 키워드를 선택해야하고 ( '클래스'를 선택한 경우) 균형이 맞아야한다는 것입니다.

다음은 클래스 함수의 재정의 동작 중 일부를 보여주는 스 니펫입니다.

class MyClass {
    class func myFunc() {
        println("myClass")
    }
}

class MyOtherClass: MyClass {
    override class func myFunc() {
        println("myOtherClass")
    }
}

var x: MyClass = MyOtherClass()
x.dynamicType.myFunc() //myOtherClass
x = MyClass()
x.dynamicType.myFunc() //myClass

4
아하, 클래스 함수가 ​​동적으로 전달된다는 매우 중요한 점! 그러나 그러한 예를 제시 할 수 있습니까? 수업 명을 어딘가에 써야합니까? 그렇다면 왜 그 클래스의 구현을 정적으로 선택하지 않습니까?
Jean-Philippe Pellet

1
또 다른 보완 질문 : 당신은 어디서 견적을 얻었습니까?
Jean-Philippe Pellet

내 이해는 클래스 함수가 ​​후드 아래에서 objc + 메소드와 거의 동일하게 작동한다는 것입니다.
Connor

1
여기에 더 간단한 답변 링크를 제공 할 수 있습니까? stackoverflow.com/questions/29636633/…
allenlinli

1
@ 위 ... 당신이 사용하는 경우의 예에서 장 PhilippePellet static func myFunc()대신 class func myFunc다음과 같은 오류 리터를 얻을 것이다 당신 : 정적 메서드를 재정의 할 수 없습니다 . 왜? 마치로 표시된 것처럼 보이기 때문입니다 final. 자세한 내용은. 아래 nextD의 답변을 참조하십시오. 또한 다음 x.dynamicType으로 대체되었습니다type(of:x)
Honey

246

더 명확하게하기 위해 여기에 예를 들겠습니다.

class ClassA {
  class func func1() -> String {
    return "func1"
  }

  static func func2() -> String {
    return "func2"
  }

  /* same as above
  final class func func2() -> String {
    return "func2"
  }
  */
}

static func ~와 같다 final class func

이기 때문에 final하위 클래스에서 아래와 같이 재정의 할 수 없습니다.

class ClassB : ClassA {
  override class func func1() -> String {
    return "func1 in ClassB"
  }

  // ERROR: Class method overrides a 'final` class method
  override static func func2() -> String {
    return "func2 in ClassB"
  }
}

18
당신은 챔피언, 큰 대답 ..i이 차이를 찾고 있었다 .. 제이크 !!
Abhimanyu Rathore

5
완전한. 감동적인.
Mehul

5
정답으로 표시해야합니다. 청초한!
abhinavroy23

1
최고의 설명! 이것은 나를 또 다른 의심으로 이끌었다. '클래스 펑크'를 사용해야하는 명백한 이유가 있습니까? 'func'만 사용하면 같은 방식으로 재정의 될 수 있으므로 차이점은 무엇입니까?
Marcos Reboucas

1
@MarcosReboucas 귀하의 질문을 올바르게 이해하면 둘 다 재정의 할 수 있지만 class func정상과 다릅니다 func. 그러나 func인스턴스 / 객체를위한 것이며 다음 class func과 같은 클래스를 통해 액세스 할 수 있습니다.ClassA.classFunc()
Jake Lin

78

나는 놀이터에서 몇 가지 실험을하고 결론을 얻었습니다.

TL; DR 여기에 이미지 설명을 입력하십시오

보시다시피의 경우 또는 class의 사용 은 습관의 문제입니다.class funcstatic func

설명이있는 운동장 예 :

class Dog {
    final func identity() -> String {
        return "Once a woofer, forever a woofer!"
    }

    class func talk() -> String {
        return "Woof woof!"
    }

    static func eat() -> String {
        return "Miam miam"
    }

    func sleep() -> String {
        return "Zzz"
    }
}

class Bulldog: Dog {
    // Can not override a final function
//    override final func identity() -> String {
//        return "I'm once a dog but now I'm a cat"
//    }

    // Can not override a "class func", but redeclare is ok
    func talk() -> String {
        return "I'm a bulldog, and I don't woof."
    }

    // Same as "class func"
    func eat() -> String {
        return "I'm a bulldog, and I don't eat."
    }

    // Normal function can be overridden
    override func sleep() -> String {
        return "I'm a bulldog, and I don't sleep."
    }
}

let dog = Dog()
let bullDog = Bulldog()

// FINAL FUNC
//print(Dog.identity()) // compile error
print(dog.identity()) // print "Once a woofer, forever a woofer!"
//print(Bulldog.identity()) // compile error
print(bullDog.identity()) // print "Once a woofer, forever a woofer!"

// => "final func" is just a "normal" one but prevented to be overridden nor redeclared by subclasses.


// CLASS FUNC
print(Dog.talk()) // print "Woof woof!", called directly from class
//print(dog.talk()) // compile error cause "class func" is meant to be called directly from class, not an instance.
print(Bulldog.talk()) // print "Woof woof!" cause it's called from Bulldog class, not bullDog instance.
print(bullDog.talk()) // print "I'm a bulldog, and I don't woof." cause talk() is redeclared and it's called from bullDig instance

// => "class func" is like a "static" one, must be called directly from class or subclassed, can be redeclared but NOT meant to be overridden.

// STATIC FUNC
print(Dog.eat()) // print "Miam miam"
//print(dog.eat()) // compile error cause "static func" is type method
print(Bulldog.eat()) // print "Miam miam"
print(bullDog.eat()) // print "I'm a bulldog, and I don't eat."

// NORMAL FUNC
//print(Dog.sleep()) // compile error
print(dog.sleep()) // print "Zzz"
//print(Bulldog.sleep()) // compile error
print(bullDog.sleep()) // print "I'm a bulldog, and I don't sleep."

7
class함수의 동적 디스패치 와 정적 바인딩의 또 다른 대답에서 주된 차이점으로 언급 된 사례는 다루지 않습니다 static.
Jean-Philippe Pellet

1
기능 이해에 대한 훌륭한 설명.
Yucel Bayram

33
하지인가 class func재정의?
Iulian Onofrei

9
정적 메서드를 재정의하려고하면 오류가 발생합니다. 그러나 클래스 메서드를 재정의 할 있습니다. 허용 된 답변보기
Honey

8
class func무시할 수 있습니다. 그렇지 않으면 나는 이것을 투표했다; 연구와 모범을 사랑하십시오!
Ben Leggiero

52

유형 변수 속성을 선언하려면 static선언 수정자를 사용하여 선언을 표시하십시오 . class서브 클래스가 수퍼 클래스의 구현을 재정의하도록 클래스가 선언 수정자를 사용하여 유형 계산 속성을 표시 할 수 있습니다 . 유형 속성은 유형 속성에서 설명합니다.

참고
클래스 선언에서, 키워드는 static모두로 선언 표시하는 것과 같은 효과가 classfinal선언 수정합니다.

출처 : Swift 프로그래밍 언어-유형 변수 속성


5
문제는 '정적 func'과 'class func'에 관한 것입니다. 타입 속성에 대해서는 묻지 않습니다. 따라서 이것은 질문에 대한 답이 아닙니다. 그러나 속성과 관련하여 이러한 키워드의 맥락을 이해하는 것이 중요합니다.
etayluz

이 답변은 단순히 잘못된 질문에 대한 것일 수 있습니다.
Fattie

15

apple이 발행 한 Swift 2.2 Book에 따르면 :

static방법의 func 키워드 앞에 키워드를 작성하여 유형 방법을 나타냅니다 . 클래스는 또한 class키워드 사용하여 서브 클래스가 수퍼 클래스의 해당 메소드 구현을 대체 할 수있게 합니다.”


10

Swift2.0에서 Apple은 다음과 같이 말합니다.

"프로토콜에서 정적 키워드를 정의 할 때 항상 접 두부 유형 특성 요구 사항을 지정하십시오.이 규칙은 클래스에 의해 구현 될 때 유형 특성 요구 사항에 클래스 또는 정적 키워드를 접두어로 사용할 수있는 경우에도 적용됩니다."


5

이 예는 모든 측면을 지 웁니다!

import UIKit

class Parent {
    final func finalFunc() -> String { // Final Function, cannot be redeclared.
        return "Parent Final Function."
    }

    static func staticFunc() -> String { // Static Function, can be redeclared.
        return "Parent Static Function."
    }

    func staticFunc() -> String { // Above function redeclared as Normal function.
        return "Parent Static Function, redeclared with same name but as non-static(normal) function."
    }

    class func classFunc() -> String { // Class Function, can be redeclared.
        return "Parent Class Function."
    }

    func classFunc() -> String { // Above function redeclared as Normal function.
        return "Parent Class Function, redeclared with same name but as non-class(normal) function."
    }

    func normalFunc() -> String { // Normal function, obviously cannot be redeclared.
        return "Parent Normal Function."
    }
}

class Child:Parent {

    // Final functions cannot be overridden.

    override func staticFunc() -> String { // This override form is of the redeclared version i.e: "func staticFunc()" so just like any other function of normal type, it can be overridden.
        return "Child Static Function redeclared and overridden, can simply be called Child Normal Function."
    }

    override class func classFunc() -> String { // Class function, can be overidden.
        return "Child Class Function."
    }

    override func classFunc() -> String { // This override form is of the redeclared version i.e: "func classFunc()" so just like any other function of normal type, it can be overridden.
        return "Child Class Function, redeclared and overridden, can simply be called Child Normal Function."
    }

    override func normalFunc() -> String { // Normal function, can be overridden.
        return "Child Normal Function."
    }
}

let parent = Parent()
let child = Child()

// Final
print("1. " + parent.finalFunc())   // 1. Can be called by object.
print("2. " + child.finalFunc())    // 2. Can be called by object, parent(final) function will be called.
// Parent.finalFunc()               // Cannot be called by class name directly.
// Child.finalFunc()                // Cannot be called by class name directly.

// Static
print("3. " + parent.staticFunc())  // 3. Cannot be called by object, this is redeclared version (i.e: a normal function).
print("4. " + child.staticFunc())   // 4. Cannot be called by object, this is override form redeclared version (normal function).
print("5. " + Parent.staticFunc())  // 5. Can be called by class name directly.
print("6. " + Child.staticFunc())   // 6. Can be called by class name direcly, parent(static) function will be called.

// Class
print("7. " + parent.classFunc())   // 7. Cannot be called by object, this is redeclared version (i.e: a normal function).
print("8. " + child.classFunc())    // 8. Cannot be called by object, this is override form redeclared version (normal function).
print("9. " + Parent.classFunc())   // 9. Can be called by class name directly.
print("10. " + Child.classFunc())   // 10. Can be called by class name direcly, child(class) function will be called.

// Normal
print("11. " + parent.normalFunc())  // 11. Can be called by object.
print("12. " + child.normalFunc())   // 12. Can be called by object, child(normal) function will be called.
// Parent.normalFunc()               // Cannot be called by class name directly.
// Child.normalFunc()                // Cannot be called by class name directly.

/*
 Notes:
 ___________________________________________________________________________
 |Types------Redeclare------Override------Call by object------Call by Class|
 |Final----------0--------------0---------------1------------------0-------|
 |Static---------1--------------0---------------0------------------1-------|
 |Class----------1--------------1---------------0------------------1-------|
 |Normal---------0--------------1---------------1------------------0-------|
 ---------------------------------------------------------------------------

 Final vs Normal function: Both are same but normal methods can be overridden.
 Static vs Class function: Both are same but class methods can be overridden.
 */

산출: 모든 유형의 기능 출력


-6

이것을 유형 메소드라고하며 인스턴스 메소드와 같은 점 구문으로 호출합니다. 그러나 해당 유형의 인스턴스가 아닌 유형에 대해 유형 메소드를 호출합니다. SomeClass라는 클래스에서 형식 메서드를 호출하는 방법은 다음과 같습니다.


1
class SomeClass {class func someTypeMethod () {// 타입 메소드 구현은 여기}} SomeClass.someTypeMethod ()
Kumar Utsav

이것은 전혀 질문에 대답하지 않습니다. 키워드 staticclass키워드 의 차이점을 물었습니다 .
Doug McBride
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.