sanichdaniel의 iOS 개발 블로그
Metatype 본문
Metatype 타입이란, 타입의 타입입니다.
class, structure, or enum의 메타타입은 자신의 이름 뒤에 .Type이 옵니다.
protocol 타입의 메타타입은 이름 뒤에 .Protocol 이 옵니다.
class Some { }
let someType: Some = Some()
let metaSomeType: Some.Type = type(of: Some())
Some 타입은 Some 클래스의 인스턴스 타입이고
Some.Type은 Some 클래스 자체의 타입 = 메타타입
.self
postfix .self 를 이용하여 타입을 값으로 접근할수 있습니다.
SomeClass.self 는 SomeClass 의 인스턴스가 아닌, SomeClass 타입 자체를 리턴합니다.
SomeProtocol.self 도 런타임에 프로토콜을 채택한 타입의 인스턴스가 아니라, SomeProtocol 자체를 리턴합니다.
// "Hello World" 가 값
// String이 타입
let myString: String = "Hello World"
// String.self가 메타타입의 값
// String.Type 이 타입
let metaString: String.Type = String.self
.self 는 static metatype 을 반환합니다. 컴파일 타임의 타입
※ type(of:) 는 dynamic metatype을 반환합니다
타입의 메타타입에 init() 함수를 호출하여 인스턴스를 만들거나, 클래스 프로퍼티, 메소드를 접근할수 있습니다.
이때 class는 final 이거나, required 생성자가 있어야 합니다. 이유
class AnotherSubClass: SomeBaseClass {
let string: String
required init(string: String) {
self.string = string
}
override class func printClassName() {
print("AnotherSubClass")
}
}
let metatype: AnotherSubClass.Type = AnotherSubClass.self
let anotherInstance = metatype.init(string: "some string")
Protocol Metatype
아래 코드는 컴파일이 안됩니다.
protocol MyProtocol {}
let metatype: MyProtocol.Type = MyProtocol.self // 에러!!!
MyProtocol.Type 은 프로토콜을 채택한 타입의 메타타입(existential metatype)을 가리키기 때문입니다.
protocol MyProtocol {}
struct MyType: MyProtocol {}
let metatype: MyProtocol.Type = MyType.self // Now works!
위의 경우 metatype은 MyProtocol의 프로퍼티나 메서드만 접근이 가능하지만 정작 불리는건 MyType의 구현입니다.
프로토콜의 concrete metatype 을 접근하려면 위에서 설명했던 .Protocol 을 사용하면 됩니다.
let protMetatype: MyProtocol.Protocol = MyProtocol.self
채택이 안된 프로토콜 프로토콜 메타타입 protMetatype은 간단한 타입 체크 protMetatype is MyProtocol.Protocol 에서만 사용이 되고 실제로는 사용될일이 거의 없다.
컴파일단에서 사용된다고 한다.
실험 (출처: devmjun.github.io/archive/Meta_Type_Swift)
print("\n---------- [ Instance Type Check ] ----------\n")
let str = "StringInstance"
print(str is String) // true, str 은 String Type 의 객체, 스트링의 객체가 맞으면 참트루
print(str == "StringInstance") // true, str 은 "StringInstance" 와 동일
print(str is String.Type) // false
print(str is String.Type.Type) // false
print("\n---------- [ Type's Type check ] ----------\n")
print(type(of: str) is String) // false, String is String 과 동일.. 그니까 String == String.Type을 물어본거
print(type(of: str) == String.self) // true, str 객체의 타입은 String 그 자체, String.Type == String.Type
print(type(of: str) is String.Type) // true, str 객체의 타입은 String.Type 의 객체 String의 타입 == String.type
print("\n---------- [ Metatype's Type check ] ----------\n")
private let meta = type(of: String.self)
print(meta is String) // false
print(meta == String.self) // false
print(meta == String.Type.self) // true, String 메타타입은 String.Type
print(meta is String.Type.Type) // true, String 메타타입은 String.Type.Type 의 객체
사용되는곳
디코딩, 테이블뷰 셀 등록, 또는 객체를 생성해주는 함수에서 인자로 MetaType을 받는 케이스가 있다(ex. 팩토리)
func decode<T>(_ type: T.Type, from: Self.Input) throws -> T where T : Decodable
// typealias AnyClass = AnyObject.Type
func register(_ cellClass: AnyClass?, forCellReuseIdentifier identifier: String)
'swift' 카테고리의 다른 글
enum vs protocol as UseCase (0) | 2020.09.28 |
---|---|
Type Erasure (0) | 2020.09.28 |
initializer (0) | 2020.09.26 |
Self Type (0) | 2020.09.05 |
type(of:) (0) | 2020.09.05 |