Swift Type System

Swift 메타타입 완벽 정리

self, Self, .Type, .self의 차이와 실전 활용법

학습 날짜

2026-07-07

1. 핵심 개념 한눈에 보기

표현 이것은 용도 예시
self (소문자) 현재 인스턴스 인스턴스 메서드 내부에서 자기 자신 참조 self.name
Self (대문자) 현재 타입 프로토콜/클래스 내부에서 타입 자체 참조 Self.defaultValue
Dog.Type 메타타입 (타입) 타입 선언에 사용 ("Dog 타입 자체를 담는 타입") let t: Dog.Type
Dog.self 메타타입 값 대입/비교에 사용 ("Dog 타입 자체"를 값으로) t = Dog.self
핵심 구분
  • Dog vs Dog.Type → 둘 다 타입 (선언용)
  • Dog() vs Dog.self → 둘 다 (대입/비교용)

2. self vs Self

class Dog {
    var name = "멍멍이"

    func printSelf() {
        print(self)       // 👈 소문자: 현재 "인스턴스"
        print(self.name)  // "멍멍이"
    }

    static func printSelfType() {
        print(Self.self)  // 👈 대문자: 현재 "타입" 자체
    }
}

let dog = Dog()
dog.printSelf()           // Dog 인스턴스 출력
Dog.printSelfType()       // "Dog" 타입 출력
self (소문자)
  • 현재 인스턴스를 가리킴
  • 인스턴스 메서드 내부에서 사용
  • self.property, self.method()
Self (대문자)
  • 현재 타입을 가리킴
  • 프로토콜, 클래스 내부에서 사용
  • 상속 시 실제 타입으로 바뀜

3. .Type vs .self

// 일반적인 경우
let dog: Dog = Dog()                  // dog은 Dog의 "인스턴스"
let dogType: Dog.Type = Dog.self     // dogType은 Dog "타입 자체"를 담는 변수

print(type(of: dog))      // Dog
print(type(of: dogType))  // Dog.Type

비유로 이해하기

Dog "강아지"라는 개념 (타입 어노테이션용)
Dog.Type "강아지라는 개념을 담는 상자"의 타입
Dog.self "강아지라는 개념"을 상자에 넣은 실제 값
Dog() 실제 강아지 한 마리 (인스턴스)
올바른 사용
// 왼쪽은 타입, 오른쪽은 값
let instance: Dog      = Dog()      // ✅
let metatype: Dog.Type = Dog.self   // ✅
잘못된 사용
let wrong1: Dog      = Dog.self  // ❌ 값 타입 불일치
let wrong2: Dog.Type = Dog()     // ❌ 값 타입 불일치

4. 인스턴스에서 .self와 .Type

let a = Dog()

a.self   // ✅ 가능 - 그냥 a 자신을 반환 (의미 없음)
a.Type   // ❌ 불가능 - 문법 에러!
표현 가능? 결과
Dog.self Dog.Type 값 (타입 자체)
Dog.Type 메타타입 (타입 선언용)
a.self a 자신 (의미 없음)
a.Type 문법 에러
type(of: a) Dog.Type 값 (= Dog.self)
인스턴스의 타입을 알고 싶으면?
type(of: a)  // Dog.Type 값 반환 (= Dog.self와 동일)

5. 메타타입 비교

let a = Dog()

type(of: a) == Dog.self    // ✅ 비교 가능 → true
type(of: a) == Dog.Type    // ❌ 컴파일 에러!
표현 이것은 비교 가능?
type(of: a)
Dog.self
Dog.Type 타입
왜?

값끼리만 == 비교 가능. 타입은 비교 대상이 아님.

// 비유:
"철수" == "철수"      // ✅ 값 == 값
"철수" == String      // ❌ 값 == 타입 (말이 안 됨)

6. 메타타입 실전 활용

6.1 타입을 파라미터로 전달

func createAnimal<T: Animal>(type: T.Type) -> T {
    return type.init()
}

let dog = createAnimal(type: Dog.self)   // ✅ Dog.self를 파라미터로 전달
let cat = createAnimal(type: Cat.self)

// ❌ 잘못된 호출
let wrong = createAnimal(type: Dog.Type)  // 컴파일 에러! 타입을 값으로 전달 불가

6.2 JSON 디코딩

func decode<T: Decodable>(_ type: T.Type, from data: Data) -> T? {
    return try? JSONDecoder().decode(type, from: data)
}

let user = decode(User.self, from: jsonData)

6.3 셀 등록 (UITableView)

tableView.register(MyCell.self, forCellReuseIdentifier: "cell")
//                 ^^^^^^^^^ 타입 자체를 전달

7. 실전 예제: 네임스페이스 패턴

카카오페이의 멀티 프레임워크 리소스 관리에서 사용한 패턴:

// 프로토콜 정의
public protocol PayResourceSupports {}

public struct PayResource<Base> {
    public let base: Base
    public init(_ base: Base) { self.base = base }
}

public extension PayResourceSupports {
    // 1번: 타입에서 호출 (static)
    static var pay: PayResource<Self>.Type { PayResource<Self>.self }

    // 2번: 인스턴스에서 호출
    var pay: PayResource<Self> { PayResource(self) }
}

왜 메타타입을 반환하나?

extension PayResource where Base == UIImage {
    // static 프로퍼티!
    public static var ic_core_message: UIImage {
        UIImage(named: "ic_core_message", in: .resourceBundle, compatibleWith: nil)!
    }
}

// 사용
imageView.image = .pay.ic_core_message
흐름 분석
UIImage.pay
   │
   │  static var pay: PayResource<Self>.Type { PayResource<Self>.self }
   │                  ─────────────────────   ─────────────────────────
   │                  반환 타입: 메타타입       반환 값: 메타타입 값
   │
   ▼
PayResource<UIImage>.self  (= PayResource<UIImage> 타입 자체)
   │
   │  타입에서 static 프로퍼티 접근 가능!
   │
   ▼
.ic_core_message → UIImage 인스턴스 반환
인스턴스 반환 vs 메타타입 반환
// 인스턴스를 반환하면:
UIImage.pay  // → PayResource<UIImage>() 인스턴스
UIImage.pay.ic_core_message  // ❌ static 프로퍼티 접근 불가

// 메타타입을 반환하면:
UIImage.pay  // → PayResource<UIImage>.self (타입 자체)
UIImage.pay.ic_core_message  // ✅ static 프로퍼티 접근 가능!

8. Q&A

Q: let dog: Dog = Dog.self 해도 돼?

A: ❌ 안 됩니다. Dog.selfDog.Type 타입이고, Dog()Dog 타입입니다. 타입이 다릅니다.

Q: Dog.selfDog()랑 같아?

A: ❌ 완전히 다릅니다.
Dog() = 강아지 한 마리 (인스턴스)
Dog.self = "강아지"라는 종 자체 (타입)

Q: DogDog.Type은 같아?

A: ❌ 다릅니다.
Dog = 인스턴스의 타입
Dog.Type = 메타타입 (타입 자체를 담는 타입)

Q: type(of: a) == Dog.Type?

A: ❌ 컴파일 에러. Dog.Type은 타입이라 비교 불가.
type(of: a) == Dog.self 사용 (값 비교)

9. 최종 정리표

표현 카테고리 용도
self 현재 인스턴스 참조
Self 타입 현재 타입 참조 (프로토콜/클래스 내부)
Dog 타입 인스턴스 타입 선언
Dog.Type 타입 메타타입 선언
Dog() 인스턴스 생성
Dog.self 타입 자체를 값으로
type(of: a) 인스턴스의 타입을 값으로
기억법
  • .Type타입 (선언용) → 콜론(:) 왼쪽에 올 수 있음
  • .self (대입/비교용) → 등호(=) 오른쪽에 올 수 있음