Swift之类型引用
类型引用
在开发中,我们经常用到实例的类型,希望实例与其真正的对象类型关联,既面向对象中的多态性。接下来将通过一个例子来进行讨论,比如,定义一个Dog类,用来描述狗,如下:
1 | class Dog { |
Dog类的bark为狗叫所定义的方法,实现中直接硬编码Dog.whatDogsSay,这种方法会很不灵活,尤其是其如果作为父类被子类时。
在Swift中,可以使用type(of:)方法来访问对象实际的类型,既会返回实例对象真正的类型,所以,可以对之前的Dog进行改进,如下:
1 | class Dog { |
如上定义,结果如下:
1 | let nd = NoisyDog() |
如果向NoisyDog实例发送bark消息,结果为”Woof woof woof”。这就是type(of:)方法的作用,他会指向实例真正的类型。self表示实例,类型为NoisyDog,所以type(of:self)返回NoisyDog类,所以会调用NoisyDog类的whatDogsSay类属性。
有时候,需要传递一个对象类型作为参数:
- 声明对象的类型时,可以使用类型名加
.再加关键字Type。 - 如果使用一个对象作为值时,比如,将类型赋值给一个变量或者作为参数值传递给函数时,可以使用类型名加
self关键字,或者type(of:)方法。
例如,有一个函数dogTypeExpecter,接收Dog类型作为参数:
1 | func dogTypeExpecter(_ whattype:Dog.Type) { |
调用方式如下:
1 | dogTypeExpecter(Dog.self) |
或:
1 | let d = Dog() |
这种情况经常出现在工厂方法中,既给定某个类型,创建该类型的实例,Swift中使用init来定义初始化器,如:
1 | class Dog { |
如下为一个工厂方法来创建Dog或NoisyDog,通过参数来指明类型:
1 | func dogMakerAndNamer(_ whattype:Dog.Type) -> Dog { |
如上定义后,编译器会报错,原因是编译器无法确保Dog的每一个子类都会实现init(name:)初始化方法,所以,我们可以通过添加required关键字来强制Dog子类实现或继承该初始化方法。
1 | class Dog { |
调用结果:
1 | let d = dogMakerAndNamer(Dog.self) // d is a Dog named Fido |
在类方法中,self代表类,在实例方法中,self表示类实例,在工厂方法中,我们在返回类型中使用了Self关键字,其具有动态性,代表返回的真正类型,其也可以用在实例方法的声明中。
1 | class Dog { |
总结
type(of:):返回对象实例所指向的真正对象类型。.Type:在类型声明时使用,比如,在函数参数声明时,期望参数为Dog类型或其子类类型,可以写成Dog.Type。.self:代表一个类型,如,函数参数需要Dog.Type类型时,可以传递Dog.self。Self:在方法声明时,在返回类型中使用Self关键字,具有动态性。
附录
在Swift中,静态变量、静态方法可以使用static、class两种关键字,但是需要注意的是,static声明的无法重载,但是class关键字可以,不过class只能使用在类中,不能用在结构体、枚举等中。