2021. 3. 21. 03:25ㆍSWIFT
오늘은 개발을 진행하다 그동안 무의식적으로 자주 사용했던 self, Self에 대해 알아보려고 합니다.
자주 사용하면서 어... 제대로 알고 있는 걸까 생각이 들었고 다시 한 번, 공부하면서 정리해보고 싶어서 개념에 대해서 정리해보겠습니다 :)
Metatype이란?
우선 Metatype이란 타입의 타입이라고 부릅니다.
어...? 근데, 타입의 타입이라니 뭔가 이상하다고 생각이 들수도 있습니다.
근데 잘 생각해보면 Swift를 활용하면서 이렇게 Type으로 붙어서 활용했던 타입의 값들 바로 이런 값들이 Subclass의 Type입니다.
즉, 타입의 타입이 됩니다. 쉽게 말해서 값으로 활용될 수 있는 타입들입니다.
그러니깐 Subclass의 Metatype은 Subclass.Type입니다.
이제 Metatype은 어떤 느낌인지 감이 오시나요..?!
그렇다면, 여기서 self, Self은 각각 어떤 연관들이 있을까요.
self
우선 가장 친숙하고 익숙한 self를 먼저 알아보도록하겠습니다~~
self는 우선 어떤 타입을 지정하여 사용할 때, 자기 자신의 타입을 나타낼 수 있게 지정해주는 프로퍼티로 사용할 수 있습니다.
딱히 해당 class, struct를 정하면서 지정해주지 않아도 자연스럽게 지정되는 것을 알 수 있습니다.
이제 Metatype이라는 것을 알았으니, 어떤 타입의 self는 그 타입의 타입이다!!!
라고 생각하시면 될 것 같습니다. 위의 그림에서도 알 수 있죠..?!
Subclass.self는 Subclass.Type 이 되는 것입니다.
그렇다면 self가 Type인건 알겠어.. 그럼 두 개가 같은거 아닌가..? 생각하면 또 오류가 나는 것이 있습니다.
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.self가 Metatype을 가지는 값이라고 생각하면 됩니다.
Self
그렇다면 다음으로 Self에 대해서 알아보도록 하겠습니다~~
Self는 조금 더 간단한데, 자기 자신의 타입을 가르키는 용어로 사용할 수 있는 곳이 제한적입니다..!!
예를 들면, 클래스나 구조체 안에서 다음과 본인의 타입을 가리켜 return 타입을 지정하거나 클래스 프로퍼티에도 접근할 수 있는 용어로 사용할 수 있습니다.
class Something {
class var value: Int = 10
// 자기 자신의 타입을 반환한다.
func make() -> Self {
return self
}
func access() {
// 10
print(Self.value)
}
}
즉, 이렇게 클래스나 구조체 내에서 본인의 타입을 가르켜 클래스 프로퍼티에 접근하거나 본인의 타입으로 지정해 리턴하는 등의 동작을 지정해서 사용할 수 있습니다. 그러나, 사용할 수 있는 곳이 제한적이라는 점이 있습니다.
여기까지 보았을 때, self와 Self의 차이점을 알 수 있겠죠??
self는 Metatype을 리턴하는 값으로 본인의 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 |