์ด์ „์— metatype์— ๋Œ€ํ•ด ํ˜๋ ค๋“ค์—ˆ์—ˆ๋Š”๋ฐ, ์ด๋ฒˆ์— ๊ฐ„๋‹จํ•˜๊ฒŒ ์ •๋ฆฌํ•ด๋ณด๋ คํ•œ๋‹ค.

metatype์ด๋ž€?

Swift์—์„œ ์šฐ๋ฆฌ๋Š” ํŠน์ • instance์˜ Type์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.

struct SomeStruct {
    static let variable: String = "HI"
}
 
let someStruct = SomeStruct()
let someStructType = type(of: someStruct)
let someStructStaticVariable = someStructType.variable
print(someStructStaticVariable) // HI

๊ทธ๋Ÿผ ์—ฌ๊ธฐ์„œ someStructType์€ ์–ด๋–ค Type์ผ๊นŒ? ์ด๋…€์„์€ SomeStruct.Type์ด๋ผ ๋˜์–ด์žˆ๋‹ค. ๋ฐ”๋กœ ์ด๋…€์„์ด metatype์ด๋‹ค.

์ด๋ ‡๊ฒŒ ๋ฐ›์€ metaType์€, ViewController.init()์„ ํ•˜์—ฌ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ์ด๋Ÿฌํ•œ ์ ์„ ์ด์šฉํ•˜๋ฉด ์ธ์ˆ˜๋กœ metatype์„ ๋ฐ›์•„ ํ•ด๋‹น metatype์˜ instance๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.

class Apple {
    required init() {}
}
 
func createApple<T: Apple>(appleType: T.Type) -> T {
    return appleType.init()
}
 
let apple = self.createApple(appleType: Apple.self)
print(apple) // test.apple

์—ฌ๊ธฐ์„œ ๊ทธ๋Ÿฐ๋ฐ ์ธ์ˆ˜๋กœ ๋„ฃ์–ด์ค„ ๋•Œ Apple.self ๋กœ ๋„ฃ์–ด์ฃผ์—ˆ๋‹ค. ์ด๋…€์„์€ ๋ญ˜๊นŒ?

metatype์˜ Value

let a: Int = 3

์—ฌ๊ธฐ์„œ a์˜ Type์€ Int์ด๊ณ , Value๋Š” 3์ด๋‹ค. ๊ทธ๋Ÿผ class, struct, enum ์ž์ฒด์— ์ ‘๊ทผํ•œ ๋…€์„์˜ type๊ณผ value๋„ ์žˆ์ง€ ์•Š์„๊นŒ?

TypeValue์˜ˆ์‹œ
InstanceInt, String3, โ€œwansikโ€let a: Int = 3
Class, Struct ์ž์ฒดInt.Type, String.TypeInt.self, String.selflet a: Int.Type = Int.self

์ด๋Ÿฐ ์ด์œ  ๋•Œ๋ฌธ์—, createApple<T: Apple>(appleType: T.Type) -> T์—์„œ T.Type์€ class, struct, enum ์ž์ฒด์˜ metatype์˜ type์„ ๋งํ•˜๊ณ , ์‹ค์ œ ๊ฐ’์€ Apple.self๋กœ class, struct, enum ์ž์ฒด์˜ value๋ฅผ ๋„ฃ์–ด์ค€ ๊ฒƒ์ด๋‹ค.

Protocol metatype

๊ทธ๋Ÿฐ๋ฐ protocol์—์„œ๋Š” ์ด ๋…ผ๋ฆฌ๊ฐ€ ํ†ตํ•˜์ง€ ์•Š๋Š”๋‹ค.

protocol MyProtocol {}
let metatype: MyProtocol.Type = MyProtocol.self // compile Error

์ด๋Š” MyProtocol.Type์ด protocol ์ž์ฒด์˜ metatype์˜ type์„ ๊ฐ€๋ฆฌํ‚ค์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์—ฅ? ๊ทธ๋Ÿผ ๋ญ˜ ๊ฐ€๋ฆฌํ‚ฌ๊นŒ? ์ด ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๊ณ  ์žˆ๋Š” Type์˜ metatype์„ ๊ฐ€๋ฆฌํ‚จ๋‹ค. ์ฆ‰, Protocol์€ ์ถ”์ƒ ์ธํ„ฐํŽ˜์ด์Šค์ด๊ธฐ ๋•Œ๋ฌธ์—, ์‹ค์ œ ์ด๋ฅผ ์ค€์ˆ˜ํ•˜๋Š” ๋…€์„์ด ๊ตฌํ˜„์ฒด์ธ๋ฐ, ์ด๋…€์„์˜ metatype์„ ๊ฐ€๋ฆฌํ‚จ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. Apple์€ ์ด๋ฅผ existential metatype, ์‹ค์กด ๋ฉ”ํƒ€ํƒ€์ž…์ด๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค. ์ฝ”๋“œ๋ฅผ ๋ณด์ž.

protocol MyProtocol {
    static func test()
}
struct MyType1: MyProtocol {
    static func test() {
        print("my type1")
    }
}
 
struct MyType2: MyProtocol {
    static func test() {
        print("my type2")
    }
}
 
let metatype1: MyProtocol.Type = MyType1.self
let metatype2: MyProtocol.Type = MyType2.self
metatype1.test() // my type1
metatype2.test() // my type2

์ฆ‰, ์ด ๊ฒฝ์šฐ metatype1, 2 ๋ณ€์ˆ˜๋Š” MyProtocol์˜ static property ๋˜๋Š” method์—๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•ด์ง„๋‹ค. ์—„๋ฐ€ํžˆ ๋งํ•˜๋ฉด MyType struct์˜ ๊ตฌํ˜„์ฒด๊ฐ€ ๋ถˆ๋ฆฐ๋‹ค. ๊ทธ๋ž˜์„œ ์‹ค์ œ ๊ตฌํ˜„์ฒด์˜ ๊ฐ’์ด ํ˜ธ์ถœ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋Ÿผ protocol ์ž์ฒด์˜ type์€ ์–ด๋–ป๊ฒŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์„๊นŒ?

let protocolType: MyProtocol.Protocol = MyProtocol.self

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์–ป์„ ์ˆ˜๋Š” ์žˆ์ง€๋งŒ, ์‹ค์ œ ๊ธฐ๋ณธ ๊ตฌํ˜„์„ ์ ‘๊ทผํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์งˆ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ธฐ๋Š” ์–ด๋ ค์›Œ๋ณด์ธ๋‹ค.

Reference