Skip to content →

Swift의 타입과 타입의 타입

스위프트는 타입을 아주 중요하게 다루는 언어입니다. 어느 정도냐면.. 심지어 타입에도 타입이 있을 정도지요!! 그리고 이 타입의 타입을 메타타입이라고 부릅니다.

“타입의 타입”이 대체 뭔 소린지, 어디에 쓰일 수 있는지 바로 감이 오지 않을 수 있습니다. 타입만 해도 충분히 추상적인 개념인데, 그걸 또 한 번 더 추상화 시킨다니…뜬 구름 잡는 소리 처럼 느껴지는 것도 무리가 아닙니다.

하지만 차근차근 개념을 쫓아가다보면, 사실 별 것 아니란 걸 알게 되실 겁니다. 이번 포스트에서는 이 메타타입이 무엇이고 어떤 문제를 해결하는지 다뤄보도록 하겠습니다.

해결하고 싶은 문제

혹시 이런 상황에 부딪혀 보신 적 있으신가요?

class MyCell: UITableViewCell { ... }
// MyCell이란 이름의 xib파일도 있음 

let myCellNib = UINib(nibName:"MyCell", bundle: nil)
tableView.register(myCellNib, forCellReuseIdentifier: "MyCell")

---

class YourCell: UITableViewCell { ... }
// YourCell이란 이름의 xib파일도 있음
let yourCellNib = UINib(nibName:"YourCell", bundle: nil)
tableView.register(yourCellNib, forCellReuseIdentifier: "YourCell")

// 기타 등등....

딱 봐도 많은 코드가 중복되고 있습니다. 이 때 이런 생각이 들지 않나요?

‘아… MyCell이라는 타입 자체를 변수로 쓸 수 있으면 좋겠다…’

좋은 소식입니다! Swift에서는 바로 그걸 할 수 있습니다!

MyCell.self

우리는 종종 MyClass.self 같은 표기를 만날 때가 있습니다. 대표적으로 Codable들을 Encoding하거나 Decoding할 때 만나게 되죠.

let myInfo = try? JSONDecoder().decode(MyClass.self, from: data)

이 때 MyClass.self에 해당되는 부분이, 바로 “MyClass”의 타입 자체의 변수 형태입니다.

“타입 자체의 변수 형태” 라고 하니까 감이 좀 잘 안 오는 면이 있습니다. 저는 아래 코드를 보니까 이해가 확 되더라고요.

class MyViewController: UIViewController {
    class var storyboardInstance: UIViewController {
        // eg. storyboardID 기반으로 ViewController생성
    }
    var someProperty: Int = 0
}

let myViewController = MyViewController()
print(myViewController.someProperty) // Print 0
print(myViewController.storyboardInstance) // Can't Access!!

print(MyViewController.someProperty) // Can't Access!!
print(MyViewController.storyboardInstance) // 평소 쓰던 class 변수 접근법
print(MyViewController.self.storyboardInstance) // **위의 거랑 같은 거!!**

그렇습니다. SomeClass.classVariableSomeClass.self.classVariable의 줄임말 이었습니다. 우리는 SomeClass.self 라는 표기법으로 Class변수(static 변수)에 접근 할 수도 있고, class메소드(static메소드)에도 접근 할 수 있습니다.

즉, SomeClass.self의 표기법을 통해서, 우리는 “class변수와 class메소드를 가지는 어떤 객체”에 접근 할 수 있게 되는 것입니다.

type(of:type(of:)

한 걸음만 더 나아가 봅시다. 위의 코드에서 myViewController의 타입은 무엇일까요?

let myViewController = MyViewController()
print(type(of:myViewController)) // print "MyViewController"

그렇습니다. myViewController의 타입은 MyViewController 입니다. 그러면 MyViewController.self의 타입은 무엇일까요? MyViewController.self도 자신의 속성과 메소드를 지니는 객체인 이상, “이 객체의 타입은 무엇이지?”라는 질문이 자연스러워집니다. 바로 확인해 봅시다.

print(type(of:MyViewController.self)) // Print "MyViewController.Type"

그렇습니다. MyViewController.self 의 타입은 MyViewController.Type 인 것이지요.

따라서 이렇게 쓸 수 있습니다.

let aType: MyViewController.Type = MyViewController.self

여기서 MyViewController.Type을 타입의 타입, 즉 메타타입이라고 합니다.

let myVC = MyViewController()
print(type(of:MyViewController.self)) // MyViewController.Type
print(type(of:type(of:myVC)) // 위랑 같은 의미!!

이런 메타타입에도 상속의 개념이 그대로 적용됩니다. 따라서 아래와 같이 쓸 수도 있습니다.

var aVCType: UIViewController.Type = MyViewController.self

if aVCType == LoginViewController.self {
    // Do Login Process
}
else if aVCType == MyViewController.self {
    // Do MyVC Stuff...
}

결론

이상의 내용을 바탕으로, 맨 처음 우리가 당면했던 문제를 해결 해 볼까요?

extension UITableView {
     /// 전제조건 : cellType의 이름과 같은 xib파일이 있어야 함
    public func register(_ cellType: UITableViewCell.Type) {
        let cellClassName = String(describing:cellType)
        let nib = UINib(nibName: cellClassName, bundle: Bundle(for: cellType))
        register(nib, forCellReuseIdentifier: cellClassName)
    }

    public func register(cellTypes: [UITableViewCell.Type]) {
        cellTypes.forEach { register(cell: $0) }
    }
}

// 용례
tableView.register(MyCell.self)
tableView.register([MyCell.self, YourCell.self])

훨씬 깔끔하게 tableViewCell을 등록 할 수 있게 되었네요.

타입과 메타타입의 관계는 일단 이해하고 나면 별 것 아니지만, 굉장히 추상적인 개념이기 때문에, 이 글을 읽는 것 만으로는 헷갈림이 쉽게 가시지 않을 수 있습니다. 모쪼록 위의 코드 예제들을 조금씩 변형해서 Xcode Playground에서 다양한 형태로 만져보시기 바랍니다.

참고문헌

  1. Swift Meta-Type : 스위프트 공식 문서
  2. type(of:T) : type(of)함수의 애플 공식문서
  3. Understanding Swift Metatypes

Published in Basics 프로그래밍

Comments

댓글 남기기

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d 블로거가 이것을 좋아합니다: