[Swift] Type Properties

강의를 들으며 나온 키워드 중 하나인 Type Properties에 대해 알아보려 한다.

이 글은 Zedd님의 블로그 글을 보며 정리하는 글입니다.

Type Properties

들어가기전에 일단 인스턴스 프로퍼티가 뭔지는 알아야 하지 않겠는가?
인스턴스 프로퍼티란 특정 타입의 인스턴스에 속하는 프로퍼티이다.(???)

지금까지 우리가 말해왔던, 특정한 구조체, 클래스에 속하는 저장 프로퍼티연산프로퍼티가 바로 인스턴스 프로퍼티라고 한다. (아하!)

그리고 프로퍼티를 타입 자체와 연결할 수 도 있다.
이러한 프로퍼티를 Type Property(타입 프로퍼티)라고 한다.

타입 프로퍼티는 모든 타입이 사용할 수 있는 상수 프로퍼티(constants property) 또는 글로벌 변수 프로퍼티와 같이 특정 타입의 모든 인스턴스에 공통적인 값을 정의하는데 유용하다.(예를 들자면 C의 static과 같은 변수)

저장 타입 프로퍼티(Stored Type Property) 는 변수 또는 상수일 수 있다.
연산 타입 프로퍼티(Computed Type Property)는 Computed instance property와 같이 항상 변수 프로퍼티로 선언된다.

하지만, 저장 인스턴스 프로퍼티와 다르게 저장 타입 프로퍼티는 항상 기본값을 줘야 한다. 왜냐하면, 초기화 시에, 타입 자체에는 저장 타입 프로퍼티에 값을 할당할 이니셜라이저가 없기 때문이다!

그러니까 static으로 선언하게 될 경우에는 이니셜라이저가 없기 때문에 선언과 동시에 초기화를 진행해야 한다라는 뜻인듯 하다.

위의 과정을 정리해보자면
1. 프로퍼티를 타입 자체에 연결할 수 있는데, 그게 타입 프로퍼티임.
2. 타입 프로퍼티에는, 저장 타입 프로퍼티연산 타입 프로퍼티가 있음.
3. 저장 타입 프로퍼티에는 상수/변수일 수 있다.
4. 연산 타입 프로퍼티는 무조건 변수로 선언해야 한다. -> var로만 선언이 가능하다. (애초에 연산을 하면 값이 바뀔텐데 당연한 소리다.)

C와 Objective-C에서는 타입과 연결된 static 상수와 static 변수를 정의할 수 있다.
근데, Swift에서 타입 프로퍼티는 타입 정의의 일부로 타입의 외부 중괄호 안에 쓰여지며, 각 타입 프로퍼티는 명시적으로 지원하는 타입으로 범위가 지정되게 된다.
(이게 뭔소리야)

static 키워드를 사용하여 타입 프로퍼티를 정의할 수 있다.
클래스 타입에 대한 연산 타입 프로퍼티의 경우 class 키워드를 사용하여 서브 클래스가 슈퍼클래스의 구현을 재정의(override) 할 수 있다.

뭔소린지 하나도 모르겠으니 코드를 보면서 이해를 어떻게든 해보자.

구조체에 대한 static

struct SomeStruct {
    static var storedTypeProperty = "Some Value."
    static var computedTypeProperty: Int {
        return 1
    }
}

일단 SomeStruct 라는 구조체를 선언했다.
그리고 그 안에는 static 키워드를 사용한게 있다.
static 을 사용하지 않았으면 그냥 저장 인스턴스 프로퍼티와 연산 인스턴스 프로퍼티일 것이다. 하지만 위 코드에는 static이 붙었다.
그래서 얘내는 타입 프로퍼티라는 것을 알 수 있다.

storedTypeProperty는 대충 봐도 저장 타입 프로퍼티로 보인다.
저장 인스턴스 프로퍼티와는 다르게 기본값 을 준 것을 볼 수 있다.

다른 예제도 살펴보자.

열거형에 대한 static

enum SomeEnumeration {
    static var storedTypeProperty = "Some Value."
    static var computedTypeProperty: Int {
        return 6
    }
}

위 코드는 열거형을 선언했다.
그런데, 원래 저장 인스턴스 프로퍼티는 구조체와 클래스에서만 사용이 가능하다고 되어있다. 하지만 저장 타입 프로퍼티는 열거형에서 사용이 가능하다.
static 키워드를 사용해서 기본값을 준 것을 볼 수 있다.

다른 것도 살펴보자.

클래스에 대한 static

class SomeClass {
    static var storedTypeProperty = "Some Value."
    static var computedTypeProperty: Int {
        return 27
    }
    
    class var overrideableComputedTypeProperty: Int {
        return 107
    }
}

아까 위에서 말한것을 다시 떠올려보자

클래스 타입에 대한 연산 타입 프로퍼티의 경우, class 키워드를 사용하여 서브클래스가 슈퍼클래스의 구현을 재정의(override) 할 수 있다.

일단 평범하게 저장 타입 프로퍼티와 연산 타입 프로퍼티가 나온게 보일 것이다.
근데 아래 하나가 더 있다. static이라는 키워드가 붙지 않고, class 키워드가 붙었다.

구현을 재정의 할 수 있다라는 말을 풀어서 쓴다면, SomeClass를 상속받은 어떤 클래스는, class 키워드가 붙은 저 overrideableComputedTypeProperty 라는 연산 타입 프로퍼티를 재정의 할 수 있다라는 의미이다.

자자, 진정하고 또 예제로 살펴보면 된다;

class ChildClass : SomeClass {
    override class var overrideableComputedTypeProperty: Int {
        return 222
    }
}

이 소리다.
그러니까 상속을 받은 자식 클래스에서 static 키워드로 선언하지 않고 class 키워드로 선언한 연산 타입 프로퍼티를 재정의 할 수 있다라는 의미이다.

반대로 class 키워드가 안붙은 연산 타입 프로퍼티를 재정의 하게 된다면 어떻게 될까?

이렇게 에러가난다.

Querying and Setting Type Properties

우리가 인스턴스 프로퍼티에서 했던 것처럼, 타입 프로퍼티 역시 조회와 값 세팅은 .(dot)을 통해 이루어진다.
근데, 인스턴스 프로퍼티와는 조금 다른점이 있다.

원래 같으면

struct FixedLengthRange {
    var first: Int
    let length: Int
}

var rangeOfThreeItems = FixedLengthRange(first: 0, length: 3)

rangeOfThreeItems.first = 6
rangeOfThreeItems.length = 10 // error

이렇게 해당 구조체, 열거형, 클래스의 인스턴스를 만들고 그 인스턴스를 통해서 프로퍼티들에 접근을 했었다.

하지만 타입 프로퍼티는

print(SomeStruct.storedTypeProperty) // Some Value
SomeStruct.storedTypeProperty = "Another Value"
print(SomeStruct.storedTypeProperty) // Another Value

print(SomeEnumeration.computedTypeProperty) // 6
print(SomeEnumeration.storedTypeProperty) // 27

이렇게 타입 자체의 이름을 치고, .(dot)을 통해 프로퍼티에 접근한다.

프로퍼티를 타입 자체와 연결할 수 도 있다.
이러한 프로퍼티를 Type Property(타입 프로퍼티)라고 한다.

이제 이 말을 조금은 이해할 수 있겠다.

오늘은 Type Property에 대해 알아보았다.

좋은 웹페이지 즐겨찾기