在Swift中能够表示 “任意” 这个概念的除了 Any 和 AnyObject 以外,还有一个AnyClass。我们能够使用AnyClass协议作为任意类型实例的具体类型。AnyClass在Swift中被所定义:
[javascript] view plain copy
1. typealias AnyClass = AnyObject.Type
通过AnyObject.Type这种方式所得到是一个元类型 (Meta)。在声明时我们总是在类型的名称后面加上.type,比如:Person.type代表的是A这个类型的类型。也就是说,我们可以声明一个元类型来存储Person这个类型本身,而在从Person中取出其类型时,我们需要使用到.self:
[javascript] view plain copy
1. class Person {
2.
3. }
4. let type: AnyClass = Person.self //Person.Type
注意:其实在 Swift中,.self可以用在类型后面取得类型本身,也可以用在某个实例后面取得这个实例本身。前一种方法可以用来获得一个表示该类型的值,这在某些时候会很有用; 而后者因为拿到的实例本身,所以暂时似乎没有太多需要这么使用的案例。
如果Person中有一个类方法时,我们就可以通过type来对其进行调用了:
[javascript] view plain copy
1. class Person {
2. class func age() -> Int {
3. return 24
4. }
5. }
6. let type: AnyClass = Person.self
7.
8. //1:
9. (type as! Person.Type).age()
10.
11. //2:
12. let type2: Person.Type = Person.self
13. type2.age()
AnyClass的使用场景
元类型可以变得非常灵活和强大,而且在我们编写某些框架性的代码时会非常方便。比如我们想要传递一些类型的时候,我们可以使用AnyClass进行处理,那么就不需要不断地去改动代码了。下面的这个例子中虽然我们是用代码声明的方式获取了SearchViewController和MessageViewController的元类型,但是其实这一步骤完全可以通过读入配 置文件之类的方式来完成的。而在将这些元类型存入数组并且传递给别的方法来进行配置这一点上,元类型编程就非常棒而且很难被替代:
[javascript] view plain copy
1. class SearchViewController: UIViewController {
2.
3. }
4. class MessageViewController: UIViewController {
5.
6. }
7.
8. let vcTypes: [AnyClass] = [SearchViewController.self,
9. MessageViewController.self]
10.
11. func setupViewControllers(_ vcTypes: [AnyClass]) {
12. for vcType in vcTypes {
13. if vcType is UIViewController.Type {
14. let vc = (vcType as! UIViewController.Type).init()
15. print(vc)
16. }
17. }
18. }
19.
20. setupViewControllers(vcTypes)
21. /*
22. <__lldb_expr_160.SearchViewController: 0x7ff265703060>
23. <__lldb_expr_160.MessageViewController: 0x7ff265602c10>
24. */
这么一来,我们完全可以搭好框架,可以在不触及Swift编码的情况下,很简单地完成一系列复杂操作了。
另外,在 Cocoa API中我们经常遇到需要输入一个AnyClass,我们应该使用.self的方式来获取对应的类型。如注册tableView的可重用cell时:
[javascript] view plain copy
1. tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
注意:.Type 表示的是某个类型的元类型,而在Swift中,除了class,struct和enum这三个类型外,我们还可以定义protocol。对于protocol来说,有时候我们也会想取得协议的元类型。这时我们可以在某个protocol的名字后面使用.Protocol 来获取,使用的方法和 .Type是类似的。