[SWIFT] Metatype - self, Self, Type

2021. 3. 21. 03:25SWIFT

반응형

오늘은 개발을 진행하다 그동안 무의식적으로 자주 사용했던 self, Self에 대해 알아보려고 합니다.

자주 사용하면서 어... 제대로 알고 있는 걸까 생각이 들었고 다시 한 번, 공부하면서 정리해보고 싶어서 개념에 대해서 정리해보겠습니다 :)

 

 

Metatype이란?

우선 Metatype이란 타입의 타입이라고 부릅니다.

 

어...? 근데, 타입의 타입이라니 뭔가 이상하다고 생각이 들수도 있습니다.

근데 잘 생각해보면 Swift를 활용하면서 이렇게 Type으로 붙어서 활용했던 타입의 값들 바로 이런 값들이 SubclassType입니다.

즉, 타입의 타입이 됩니다. 쉽게 말해서 값으로 활용될 수 있는 타입들입니다.

 

그러니깐 SubclassMetatypeSubclass.Type입니다.



이제 Metatype은 어떤 느낌인지 감이 오시나요..?!

그렇다면, 여기서 self, Self은 각각 어떤 연관들이 있을까요.

 

 

self

우선 가장 친숙하고 익숙한 self를 먼저 알아보도록하겠습니다~~

 

self는 우선 어떤 타입을 지정하여 사용할 때, 자기 자신의 타입을 나타낼 수 있게 지정해주는 프로퍼티로 사용할 수 있습니다.

딱히 해당 class, struct를 정하면서 지정해주지 않아도 자연스럽게 지정되는 것을 알 수 있습니다.

 

이제 Metatype이라는 것을 알았으니, 어떤 타입의 self는 그 타입의 타입이다!!!

라고 생각하시면 될 것 같습니다. 위의 그림에서도 알 수 있죠..?! 

Subclass.selfSubclass.Type 이 되는 것입니다.

 

그렇다면 selfType인건 알겠어.. 그럼 두 개가 같은거 아닌가..? 생각하면 또 오류가 나는 것이 있습니다.

class Superclass {
    func make(type: Subclass.Type) { }
}

let superclass = Superclass()

superclass.make(type: Subclass.Type)    // compile error

바로 이렇게 self랑 Type이 같다고 작성했지만 컴파일 에러가 나는 것을 확인할 수 있습니다...

 

이건 바로 헷갈릴수는 있지만 arr.append(Int)와 같은 명령어를 입력하면 역시나 컴파일 에러가 발생합니다.

이와 같은 원리로 Subclass.Type은 타입이고 Subclass.selfMetatype을 가지는 값이라고 생각하면 됩니다.

 

 

Self

그렇다면 다음으로 Self에 대해서 알아보도록 하겠습니다~~

 

Self는 조금 더 간단한데, 자기 자신의 타입을 가르키는 용어로 사용할 수 있는 곳이 제한적입니다..!!

 

예를 들면, 클래스나 구조체 안에서 다음과 본인의 타입을 가리켜 return 타입을 지정하거나 클래스 프로퍼티에도 접근할 수 있는 용어로 사용할 수 있습니다.

class Something {
    class var value: Int = 10

    // 자기 자신의 타입을 반환한다.
    func make() -> Self {
        return self
    }
    
    func access() {
    	// 10
        print(Self.value)
    }
}

즉, 이렇게 클래스나 구조체 내에서 본인의 타입을 가르켜 클래스 프로퍼티에 접근하거나 본인의 타입으로 지정해 리턴하는 등의 동작을 지정해서 사용할 수 있습니다. 그러나, 사용할 수 있는 곳이 제한적이라는 점이 있습니다.

 

여기까지 보았을 때, selfSelf의 차이점을 알 수 있겠죠??

selfMetatype을 리턴하는 값으로 본인의 Metatype을 가지는 값을 나타냅니다. 즉, 자기의 타입의 타입의 값을 가집니다.

반면에 Self는 자기의 타입을 가르키는 용어로 사용할 수 있는 곳이 제한적이게 됩니다.

 

지금까지는 차이를 알아보았는데, 그렇다면 이런 것들을 활용해서 어떻게 코드를 작성할 수 있을까요?

좀 더, 타입을 활용해서 범용성있게 작성할 수 있습니다.

 

예시

예를 들어, 각 카테고리마다 필요한 CollectionViewCell이 있다고 생각해보겠습니다.

enum Category: Int {
    case following = 0
    case feed      = 1
    case follower  = 2
    
    var cellType: CategoryCollectionViewCellProtocol.Type {
        switch self {
        case .following:    return FollowingCell.self
        case .feed:         return FeedCell.self
        case .follower:     return FollowerCell.self
	}
    }
}

이렇게 MetaType을 활용해서 각 Category에 해당하는 Cell의 Metatype을 리턴하는 함수를 만들 수 있습니다.

그러면 각 IndexPath마다 필요한 Cell으로 캐스팅해서 사용, register하는 코드를 작성할 수 있게 됩니다.

 

또한, 동적으로 현재의 Metatype을 알아내서 사용할 수 있는 함수가 존재합니다..!!

자주 사용했을 수도 있는데, 이 역시도 Metatype과 관련된 함수였습니다~

 

바로 런타임 중에 타입을 알아낼 수 있는 것인데,

class Subclass {
    class var value: Int = 10
}

let subclass = Subclass()

type(of: subclass)        // Subclass.Type
type(of: subclass).value  // 10
Subclass.value            // 10

이렇게 작성을 할 수 있습니다. 

즉, type(of:)는 Metatype을 가져오는데 이를 이용해서 해당 값의 클래스 프로퍼티에 접근이 가능합니다.

또한 Subclass의 정적 타입으로도 클래스 프로퍼티에 접근하는 것이 가능합니다.

 

이렇듯, 여러가지 방법을 이용해서 그 때에 맞게 활용할 수 있습니다..!!

지금까지는 그냥 고쳐주는대로 사용하면서 당연히 그렇겠지..라고 넘어갔던 것들이 있었는데

이렇게 정리를 하고 넘어가니깐 어떤 개념인지 와닿는 것 같네요 :)

 

도움이 되었으면 좋겠습니다~~ :)

반응형

'SWIFT' 카테고리의 다른 글

[SWIFT] Swift Method Dispatch - Dynamic, Static  (0) 2021.06.11
[SWIFT] URL encoding (URL nil이 될 때 - addingPercentEncoding)  (0) 2021.06.05
[SWIFT] Property Wrapper  (0) 2021.03.14
[SWIFT] OptionSet  (0) 2021.03.07
[SWIFT] Swift SOLID 원칙  (0) 2021.02.27