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
只能使用在类中,不能用在结构体、枚举等中。