Yuan type
A metatype is the type of a type. For example, if we say that 5 is an Int, then 5 is a value of Int. But if I ask how much memory an Int takes up, it doesn’t have to do with a particular value, it has to do with information about the type. If you are writing a function, return the size of the instance memory of a type. So the argument in this case is a type of data, and the type of data can be either directly specified like an Int, or it can be taken from a value, like the type of the value 5. The type data, in this case, is the type of a type, expressed in the term metaType.
The Type and the self
Meta types in Swift are represented by.type. For example, int. Type is the meta-type of Int. Types and values have different forms, like the relationship between Int and 5. The same is true of metatypes..type is a Type, and.self of the Type is the value of the mettype.
let intMetatype: Int.Type = Int.self
Copy the code
A metatype has only one corresponding value, so it is often written incorrectly:
types.append(Int.Type)
types.append(Int.self)
Copy the code
Int.Type is the name of a Type, not a value. Because you wouldn’t write:
numbers.append(Int)
Copy the code
AnyClass
Once you get the metatype, you can access static variables and static methods. We use metatypes a lot, but sometimes Xcode helps us hide these details. For example, one method we often use for tableView:
func register(AnyClass? , forCellReuseIdentifier: String)
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
Copy the code
AnyClass is a meta-type:
typealias AnyClass = AnyObject.Type
Copy the code
AnyClass is an alias for a meta-type of any type. When we access static variables, we also access them through metatype, but Xcode helps us omit.self. The following two ways are equivalent. I don’t think anyone would want to write self if it wasn’t confusing.
Int.max
Int.self.max
Copy the code
type(of:) vs .self
We mentioned earlier that we can get metatype values from both type(of:) and.self. So what’s the difference between these two approaches?
let instanceMetaType: String.Type = type(of: "string")
let staicMetaType: String.Type = String.self
Copy the code
.self fetches a static metatype, whatever type is declared. Type (of:) takes the runtime metatype, which is the type of this instance.
let myNum: Any = 1
type(of: myNum) // Int.type
Copy the code
Protocol
Many people get the Protocol meta-type wrong. Protocol itself is not a type, and only an object that implements Protocol has a type object. So protocol. self is not equal to protocol. Type. If you write down the code below you will get an error:
protocol MyProtocol {}let metatype: MyProtocol.Type = MyProtocol.self
Copy the code
The correct understanding is that myprotocol. Type is also a valid metatype, so it needs to be a hosted Type metatype. So this is fine:
struct MyType: MyProtocol {}let metatype: MyProtocol.Type = MyType.self
Copy the code
So what type is protocol. self? To satisfy your curiosity, Apple has created a category for you:
let protMetatype: MyProtocol.Protocol = MyProtocol.self
Copy the code
A practical
Let me give you an example just to familiarize you with the use of meta-types. Suppose we have two Cell classes and want a factory method that initializes objects by type. Here are two Cell classes:
protocol ContentCell {}class IntCell: UIView.ContentCell {
required init(value: Int) {
super.init(frame: CGRect.zero)
}
required init? (coder aDecoder:NSCoder) {
fatalError("init(coder:) has not been implemented")}}class StringCell: UIView.ContentCell {
required init(value: String) {
super.init(frame: CGRect.zero)
}
required init? (coder aDecoder:NSCoder) {
fatalError("init(coder:) has not been implemented")}}Copy the code
The implementation of the factory method looks like this:
func createCell(type: ContentCell.Type) -> ContentCell? {
if let intCell = type as? IntCell.Type {
return intCell.init(value: 5)}else if let stringCell = type as? StringCell.Type {
return stringCell.init(value: "xx")}return nil
}
let intCell = createCell(type: IntCell.self)
Copy the code
Of course we can also use type inference, combined with generics:
func createCell<T: ContentCell>(a) -> T? {
if let intCell = T.self as? IntCell.Type {
return intCell.init(value: 5) as? T
} else if let stringCell = T.self as? StringCell.Type {
return stringCell.init(value: "xx") as? T
}
return nil
}
// Now infer the metatype to be used based on the return type
let stringCell: StringCell? = createCell()
Copy the code
The Dequeue for the tableView in Reusable uses a similar implementation:
func dequeueReusableCell<T: UITableViewCell>(for indexPath: IndexPath, cellType: T.Type = T.self) -> T
where T: Reusable {
guard let cell = self.dequeueReusableCell(withIdentifier: cellType.reuseIdentifier, for: indexPath) as? T else {
fatalError("Failed to dequeue a cell")}return cell
}
Copy the code
When dequeued, we can infer from the target type, no need to declare additional metatype:
class MyCustomCell: UITableViewCell.Reusable
tableView.register(cellType: MyCustomCell.self)
let cell: MyCustomCell = tableView.dequeueReusableCell(for: indexPath)
Copy the code
Reference
- Whats Type And Self Swift Metatypes
- ANYCLASS, metatype and.self
- Weibo: @Zhuo without a story
- If you want to communicate with me more closely, you can also join my knowledge planet: iOS Programmer Protection Society