Swift metatypes
struct Shop {
let name: String
func deactivate(by name: String) {}
}
let myShop: Shop = Shop()
We can get the metatype by using typeOf(Object)
If we use snippet above, we can call typeOf(myShop) //Shop.Type
. Shop.Type
is the metatype of Shop
Using typeOf
we can access to all class properties and method, including init()
We can define metatype for structs, classes, enums and protocols.
type(of:)
is dynamic metatypes while .self
is static metatypes
static metatypes is to determine what is the compile time type of an object.
we use static metattypes in few places such as table view cell registration
tableView.register(MyTableViewCell.self, forReuseIdentifier: "myCell")
Protocol metatypes behave different than any other metatypes. Because it’s not referring to the protocol itself but to the metatype of whatever type that is conforming that protocol. Apple call this existensial metatype
Highlights
If that sounds confusing, you can see it like this: Just like String
is the type and "Hello World"
is the value of an instance, String.Type
is the type and String.self
is the value of a metatype
On the other hand, type(of)
will return a dynamic metatype, which is the metatype of the object’s real, runtime type.
let myNum: Any = 1 // Compile time type of myNum is Any, but the runtime type is Int.
type(of: myNum) // Int.type
The reason for that is that in the context of protocols, MyProtocol.Type
doesn’t refer to the protocol’s own metatype, but the metatype of whatever type is inheriting that protocol. Apple calls this an existential metatype.
protocol MyProtocol {}
struct MyType: MyProtocol {}
let metaType: MyProtocol.Type = MyType.self
In this case, metatype
only has access to MyProtocol
class properties and methods, but MyType's
implementations will be called. To get the concrete metatype of the protocol type itself, you can use the .Protocol
suffix. That’s basically the same as using .Type
on other types.