본문 바로가기

iOS/Swift

Metatype(.self, .Type, .Protocol)

오늘 강의를 듣는데 .self가 나오면서 메타타입이 나오는거에요

그래서 어 그게 머지? 하고 찾다가 시작된 블로그…글..임미다..

글을 쓰기전에 앞서서… 소들이님이랑 수진날진님.. 블로그로 이해한 후 작성하려 했으나…. 쓰다보니까 따라쓰기가 되어 가더라구요 ㅠㅠ(너무 잘 정리하셔따..)

그래서 혹시 보시는 분들은 ㅇ아래 링크타고 들어가서 보시면 훨~씬 이해가 잘 되실껍니다!!!

Swift) Metatype(.self, .Type, .Protocol) 정복하기 (1/2)

 

Swift) Metatype(.self, .Type, .Protocol) 정복하기 (1/2)

안녕하세요, 소들입니다 :D 오늘은 바로 2월 1일 설날이랍니다 눈 뜨자마자 갑자기 Metatype 포스팅이 하고 싶어져서 포스팅을 하고 있는 사람이라고 볼 수 있겠습니다 그 있잖아요 개발하다가 보

babbab2.tistory.com

[Swift] .self, .Type .Protocol, Self가 뭔디요!

 

[Swift] .self, .Type .Protocol, Self가 뭔디요!

Swift의 메타타입 (Metatype)을 알아보자

sujinnaljin.medium.com

Meta type이란????

  • 타입의 타입

??????????????????? 먼 개솔임 이라고 할 수 있는데 딱 이게 맞는 표현이더라구여.

메타타입이.. 타입인데.. 그게 타입의 타입인거임!

그니까 그 타입 자체가 바로 메타타입이라는거져!

struct Human {
    static let name = "gildong"
    var age = 25
}

let gildong = Human()

print(Human.name)
print(gildong.age)

let gildongType = type(of: gildong)
print(gildongType.name)

 

위 예의 구조체에는 타입 프로퍼티와 인스턴스 프로퍼티가 있습니당

static으로 선언된 타입 프로퍼티 name은 타입 자체를 통해 호출을 합니다!

만약에 print(gildong.name) 와 같은 방법으로 호출을 시도하면 바로 에러를 토하죠 ㅠ

이때 type(of:) 를 이용하면 타입 자체를 저장할 수 있습니다

let gildongType = type(of: gildong)
print(gildongType.name)

 

타입을 보면 Human.Type 타입이죠? 이게 바로 Human의 메타타입입니다!

그리고 이는 Human이라는 타입 자체이기 때문에 타입 프로퍼티의 호출이 가능!

 

그래서 메타타입은 .Type이 붙는걸 알 수 있음!!!!!

 그리고 위 코드를 보면 알겠찌만 Human.Type은 하나의 타입을 나타내는거임

(이름도 메타타입이네 ㅋㅋ)

중간 정리!

Human 타입이다 → Human 으로 생성한 인스턴스의 타입임 (인스턴스 멤버 사용 )

Human 메타 타입이다 → Human 타입 자체를 가리밐ㅁ ( 타입 멤버 사용 )

.self

그럼 다음으로 언제 사용하면 좋을까?

protocol Human {
    var job: String { get set }
    init(_ job: String)
}
struct Teacher: Human {
    var job: String
    
    init(_ job: String) {
        self.job = job
    }
}
struct Student: Human {
    var job: String
    
    init(_ job: String) {
        self.job = job
    }
}

func create<T: Human>(type: T.Type) -> T {
    switch type {
    case is Teacher.Type:
        return T.init("teacher")
    case is Student.Type:
        return T.init("student")
    default:
        fatalError("👾")
    }
}

 

메타타입과 제네릭을 이용해서 타입별로 다른 작업을 하게 할 수 있습니다!

그럼 create 함수의 type 파라미터 자리에는 T의 메타타입이 들어가야 하겠죠?

킹치만 아래와 같이 넣으면 에러가 발생하는데 그 이유가 멀까요??

let teacher = create(type: Teacher.Type)     
// Type 'Teacher.Type' cannot conform to 'Human'

 

좀만 생각해보면 알 수 있는데 메타타입은 뭐였죠?? 타입입니다!

그러니까 위 코드는 다르게 말하면 create(type: Int) 뭐 이런느낌이라는 거죠

파라미터에 타입 대신 값이 들어가야 한다는 겁니다!!!!!!!

이때 사용할 수 있는게 .self 입니다

다르게 말하자면 metatype의 값을 얻기 위해서 .self를 이용할 수 있습니다!!

Static Metatype VS Dynamic Metatype

여기서 좀 더 깊게 들어가보자면 .self 는 static metatype이라고도 부릅니다.

compile time에서의 object type을 다르게 부르는 것이기도 합니당

평소에 타입 프로퍼티에 접근할 때 Human.name 으로 하던거 기억 나시나여?

이게 원래는 Human.self.name 에서 .self가 생략된 것입니다!!!

요약하자면 타입 프로퍼티나 클래스에 접근할때마다 static metatype을 사용해 왔던것임!!!

여기서 이걸 공부한 이유가 나오는데 UIKit에서 테이블 뷰에서 셀을 등록할 때 register를 사용하자나여

func register(
    _ cellClass: AnyClass?,
    forCellReuseIdentifier identifier: String
)

register의 AnyClass도 메타타입인거 알고 계셨나요??

 

그래서 사용할 때 항상 .self를 붙혔던거임!!!! ㅋㅋㅋ아 알고나니까 속이 시원하네 ㅋㅋ

tableView.register(MyTableViewCell.self, forCellReuseIdentifier: "MemberCell")

 

그럼 type(of:)가 반환하는 dynamic metatype은 뭐에요?

얘는 object의 metatype → runtime type 입니다!

let anyType: Any = 10
type(of: anyType)

anyType은 컴파일 시점에서 타입은 Any이지만 런타임 타입은 Int

밑 코드의 결과는 Int.Type 이자나여

그러니까 anyType의 타입은 런타임 시점에서 결정되는데 2번째 코드가 동작하는 것을 보면

type(of:) 메서드는 런타임 시점에서 동작한다는 것을 알 수 있습니다

그래서 한번 정리해보자면

type(of:)

  • dynamic metatype
  • 런타임 시점에서 타입 결정
  • 하위 클래스의 메타타입에 접근할 시 사용

.init

  • static metatype
  • 컴파일 시점에서 타입 결정
  • 하위 클래스의 메타타입 접근을 제외한 나머지

self 말고 .self 말고 Self

진짜진짜진짜진짜로 너무 헷갈리는 self, .self, Self

오늘 얘네랑 끝을 보도록 하겠습니다… 찾아보는거 오늘이 마지막이다 진짜로

self

tableView.dataSource = self
  • 인스턴스에서 만들어지며, 해당 인스턴스를 가리킴

.self

tableView.register(MyTableViewCell.self, forCellReuseIdentifier: "MemberCell")
  • 해당 타입의 메타타입을 얻기위해 사용

Self

  • 하나의 타입으로서, 현재 속한 코드의 Type을 의미.
extension Int {
    static let zero: Self = 0
    func makeZero() -> Self {
        return Self()
    }
}

위와 같은 방법으로 Int 대신 Self 로 대신함.

이러면 타입에 의존하지 않는다는 장점이 생깁니당

class 안의 멤버들에 대해 Self 는 아래와 같은 상황에서만 나타날 수 있답니다.

  • 메소드의 return type
  • 읽기 전용 subscript의 return type
  • 읽기 전용 computed property 의 type
  • method의 body

여기까지 정리해봤구여

자세한 내용은 위에 참고한 블로그 방문해주시면 감사하겠습니다!

지적도 많이 해주세요!

감삼다!!!!!!!!!!!!!!!!!

'iOS > Swift' 카테고리의 다른 글