元类型
元类型就是类型的类型。元类型表述为metaType
。
.Type和.self
Swift中元类型用.Type
表示。比如Int.Type
就是Int
的元类型。
类型和值有着不同的形式,比如说5是个Int
类型的值。
.Type
是类型的元类型;类型的.self
是元类型的值,也就是类型本身。
1 2
| let metaTypeValue: Int.Type = Int.self
|
元类型在Swift中的应用
在Swift中,获得元类型后可以访问静态变量和静态方法。我们经常使用元类型,比如在tableView
中的AnyClass
:
1 2 3 4
| func register(AnyClass?, forCellReuseIdentifier: String) tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
typealias AnyClass = AnyObject.Type
|
AnyClass
就是一个任意类型元类型的别名。
当我们访问静态变量的时候其实也是通过元类型来访问的,只是Xcode
帮我们省略了.self
:
type(of:) 和 .self
type(of:)
和.self
都可以获得元类型的值,
1 2
| let instanceMetaType: String.Type = type(of: "string") let staicMetaType: String.Type = String.self
|
这两种方式的区别在于:
.self
获取到的是静态的元类型,声明的时候是什么类型就是什么类型
.type(of:)
获取到的是运行时的元类型
1 2 3
| let myNum: Any = 1 print("myNum.Type = \(type(of: myNum))")
|
Protocol的元类
Protocol
自身并不是一个类型,只有当一个对象实现了Protocol
后才有了类型对象。所以Protocol.self
并不等于Protocol.Type
。Protocol.Type
要成为一个有效的元类,就需要一个可承载的类型:
1 2 3 4 5 6
| protocol MyProtocol {}
let metaType:MyProtocol.Type = MyProtocol.self
struct MyType:MyProtocol {} let metaType:MyProtocol.Type = MyType.self
|
实战示例和应用
假设有两个Cell
类,想要一个工厂方法可以根据类型初始化对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| protocol ContentCell {} class IntCell:UIView,ContentCell { requeired init(value:Int) { super.init(frame:CGRect.zero) } requierd init?(coder aDecoder:NSCoder) { fatalError("init(code:) has not been implemented") } }
class StringCell:UIView,ContentCell { requeired init(value:Int) { super.init(frame:CGRect.zero) } requierd init?(coder aDecoder:NSCoder) { fatalError("init(code:) has not been implemented") } }
|
工厂方法的实现:
1 2 3 4 5 6 7 8 9 10
| func createCell(type:ContentCell.Type) -> ContentCell? { if let intCell = type as? IntCell.Type { return intCel.init(value: 0) }else if let stringCell = type as? StringCell.Type { return stringCell.init(value:"string") } return nil }
let intCell = createCell(type:IntCell.self)
|
使用泛型+类型推断:
1 2 3 4 5 6 7 8 9
| func createCell<T: ContentCell>() ->T? { if let intCell = T.self as? IntCell.Type { return intCell.init(value:0) as? T }else if let stringCell = T.self as? StringCell.Type { return stringCell.init(value: "string") as? T } return nil } let stringCell:StringCell? = createCell()
|
在Reusable
中的tableView
的dequeue
采用了类似的实现:
1 2 3 4 5 6 7
| 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 }
|
dequeue
的时候根据目标类型推断,不需要再额外声明元类型:
1 2 3
| class MyCell:UITableViewCell,Reusable tableView.register(cellType:MyCell.self) let cell:MyCell = tableView.dequeueReusableCell(for:indexPath)
|