let name = "小明" print(type(of: name)) // String这里 name 是个字符串,它的类型是 String。那么问题来了:String 这个类型,它自己的类型是什么?
let stringType: String.Type = String.self print(type(of: stringType)) // String.Type看到区别了吗?
.String.self 是一个元类型,类型是 String.Type
let stringMetatype = String.self let intMetatype = Int.self let arrayMetatype = Array<String>.self这些都是元类型,你可以把它们存储在变量里、传给函数、甚至放在数组中,就跟普通变量一样:
let types: [Any.Type] = [String.self, Int.self, Bool.self] print(types) // [String, Int, Bool]实战
// 注册自定义 Cell tableView.register(MyCustomCell.self, forCellReuseIdentifier: "MyCell")为啥不能直接传 MyCustomCell 呢?原因很简单:
let user = try JSONDecoder().decode(User.self, from: jsonData)这里的 User.self 告诉解码器:"我要解码成 User 类型的对象"。
func create<T>(_ type: T.Type) -> T where T: NSObject { return type.init() } let label = create(UILabel.self) let button = create(UIButton.self)这里通过传递元类型,让函数知道要创建什么类型的对象。
func processValue(_ value: Any) { let valueType = type(of: value) if valueType == String.self { print("这是个字符串:\(value)") } else if valueType == Int.self { print("这是个整数:\(value)") } else { print("不知道这是啥玩意:\(value)") } } processValue("Hello") // 这是个字符串:Hello processValue(42) // 这是个整数:42或者更牛逼一点,检查是否符合某个协议:
protocol Drawable { func draw() } struct Circle: Drawable { func draw() { print("画个圆") } } func checkAndDraw(_ type: Any.Type) { iflet drawableType = type as? Drawable.Type { // 这里可以调用 drawableType 的初始化方法 print("\(type) 可以画画") } else { print("\(type) 不会画画") } } checkAndDraw(Circle.self) // Circle 可以画画 checkAndDraw(String.self) // String 不会画画自定义类型的元类型
struct Person { let name: String let age: Int staticfunc create(name: String, age: Int) -> Person { returnPerson(name: name, age: age) } } let personType: Person.Type = Person.self // 可以通过元类型调用静态方法,挺神奇地 let person = personType.create(name: "小红", age: 25) print(person) // Person(name: "小红", age: 25)元类型 vs 实例类型:新手最容易搞混地地方
struct Car { let brand: String } let car = Car(brand: "Tesla") // 堆代码 duidaima.com // 这些都是不同的东西: let carInstance = car // 实例,类型是 Car let carType = Car.self // 元类型,类型是 Car.Type let carInstanceType = type(of: car) // 运行时获取的元类型,也是 Car.Type print(type(of: carInstance)) // Car print(type(of: carType)) // Car.Type print(type(of: carInstanceType)) // Car.Type小技巧:怎么获取类型名称
extension Any.Type { var typeName: String { return String(describing: self) } } print(String.self.typeName) // "String" print([Int].self.typeName) // "Array<Int>" print(Car.self.typeName) // "Car" // 非常方便这个在调试、日志记录时特别有用,我经常这么干。
// 这样效率高,编译时就确定了 let type1 = String.self // 这样效率稍低,需要运行时才知道 let type2 = type(of: someValue)所以,如果能在编译时确定类型,优先用 .self。