Swift中如何判断对象是否为指定类的子类?代码实现疑问
首先来看第一个问题:如何实现findType()函数,判断传入的实例是否是指定父类(或其子类)的实例。
你当前直接比较type(of: obj) == parent返回false,是因为type(of: raceCar)得到的是具体子类的元类型(RacingCar.Type),而parent是父类的元类型(Car.Type),这两个是不同的类型对象。要实现你的需求,我们可以利用Swift元类型的isSubclass(of:)方法,结合直接相等判断(覆盖实例就是父类本身的情况):
class Car {} class RacingCar: Car {} let raceCar = RacingCar() func findType(_ obj: Any, parent: AnyClass) { // 获取实例的动态类型,并转换为AnyClass let objDynamicType = type(of: obj) as! AnyClass // 判断:要么类型完全相等,要么是子类 let isMatch = objDynamicType == parent || objDynamicType.isSubclass(of: parent) print(isMatch) // 调用后会输出true } findType(raceCar, parent: Car.self)
另外,如果你愿意让类继承自NSObject,也可以用Objective-C的isKind(of:)方法,它会自动判断实例是否是该类或其子类的实例:
class Car: NSObject {} class RacingCar: Car {} let raceCar = RacingCar() func findType(_ obj: Any, parent: AnyClass) { if (obj as? NSObject)?.isKind(of: parent) == true { print(true) } } findType(raceCar, parent: Car.self)
接下来是第二个问题:泛型函数传入AnyClass类型参数时无效的解决办法。
你写的isTypeOf泛型函数在直接传入具体类型(比如Car.self)时能正常工作,但在getType中传入AnyClass类型的参数时失效,原因是编译器无法从AnyClass推断出泛型T的具体类型,导致obj is T无法正确执行类型检查。
有两种常见的解决方式:
方式1:去掉泛型,改用元类型判断
把isTypeOf改成和第一个问题中类似的实现,直接基于AnyClass做判断,这样不管传入什么类型的元类型都能正常工作:
func isTypeOf(_ obj: Any, parent: AnyClass) { let objDynamicType = type(of: obj) as! AnyClass if objDynamicType == parent || objDynamicType.isSubclass(of: parent) { print("true") } } func getType(parentClass: AnyClass){ isTypeOf(raceCar, parent: parentClass) // 现在可以正常打印true } getType(parentClass: Car.self)
方式2:让getType也变成泛型函数
如果想保留泛型的写法,可以把getType也定义为泛型函数,让编译器能推断出具体的类型:
func isTypeOf<T>(_ obj: Any, parent: T.Type) { if obj is T { print("true") } } // 把getType改成泛型函数 func getType<T>(parentClass: T.Type){ isTypeOf(raceCar, parent: parentClass) } getType(parentClass: Car.self) // 正常工作,输出true
这样编译器在调用getType时,会从Car.self推断出T是Car类型,obj is T就能正确判断raceCar是Car的子类实例。
内容的提问来源于stack exchange,提问作者karim

