如何在swift中检查一个对象是否是一种动态类类型?

我正在实现一个名为ofType的函数,它过滤掉给定类型的所有元素.

这是我的代码

class Animal {}
class Mammal: Animal {}
class Monkey: Mammal {}
class Pig: Mammal {}
class Human: Mammal {}

extension Array {
    func ofType<T>(_ Metatype: T.Type) -> [T] {
        return flatMap { type(of: $0) == Metatype ? $0 as? T : nil }
//      return flatMap { $0 as? T } // This is not working as the T is always the static type of the parameter,which is Animal in this example.
//      return flatMap { $0 as? Metatype } // This is not working either because of the grammar restriction.
    }
}

let animals = [Monkey(),Pig(),Human(),Mammal(),Animal()]
func animalType() -> Animal.Type {
    return Mammal.self
}
animals.ofType(animalType()).count // returns 1,expect to be 4.

在Objc中,我可以使用isKindOf()来检查对象是类的实例还是子类.在swift和as中有类似的操作,但是它们之后的类型应该是静态类型,而不是动态类型值(例如我可以写的是Mammal,但不是Mammal.self).

我不能使用类型参数T,因为在这个例子中,T等于Animal,这不是我想要的.

你对如何实现这个功能有任何想法吗?

就个人而言,我认为 @JeremyP’s suggestion使用Mirror是最好的;虽然我会做一些调整:
/// Conditionally cast `x` to a given dynamic Metatype value,taking into consideration
/// class inheritance hierarchies.
func conditionallyCast<T,U>(_ x: T,to destType: U.Type) -> U? {

  if type(of: x) is AnyClass && destType is AnyClass { // class-to-class

    let isCastable = sequence(
      first: Mirror(reflecting: x),next: { $0.superclassMirror }
    )
    .contains { $0.subjectType == destType }

    return isCastable ? (x as! U) : nil
  }

  // otherwise fall back to as?
  return x as? U
}

在这里,我们使用sequence(first:next:)从动态类型的x创建一个元类型序列,通过它可能具有的任何超类元类型(可能是第一次使用我看过的看起来不太糟糕的函数:P).另外,我们又回到了做什么?当我们知道我们没有进行类到类的转换时,它会使该函数也能使用协议元类型.

然后你可以简单地说:

extension Sequence {
  func ofType<T>(_ Metatype: T.Type) -> [T] {
    return flatMap { conditionallyCast($0,to: Metatype) }
  }
}

protocol P {}
class Animal {}
class Mammal: Animal {}
class Monkey: Mammal,P {}
class Pig: Mammal {}
class Human: Mammal,P {}

let animals = [Monkey(),Animal()]

let animalType: Animal.Type = Mammal.self
print(animals.ofType(animalType)) // [Monkey,Pig,Human,Mammal]

print(animals.ofType(P.self)) // [Monkey,Human]

假设您在Apple平台上(即可以访问Objective-C运行时),另一个选择是使用Objective-C元类方法isSubclass(of:)来检查给定的元类型是否相等,或者是否为子类另一个

import Foundation

/// Conditionally cast `x` to a given dynamic Metatype value,to destType: U.Type) -> U? {

  let sourceType = type(of: x)

  if let sourceType = sourceType as? AnyClass,let destType = destType as? AnyClass { // class-to-class

    return sourceType.isSubclass(of: destType) ? (x as! U) : nil
  }

  // otherwise fall back to as?
  return x as? U
}

这是有效的,因为在Apple平台上,Swift类构建在Obj-C类之上 – 因此Swift类的元类型是Obj-C元类对象.

相关文章

软件简介:蓝湖辅助工具,减少移动端开发中控件属性的复制和粘...
现实生活中,我们听到的声音都是时间连续的,我们称为这种信...
前言最近在B站上看到一个漂亮的仙女姐姐跳舞视频,循环看了亿...
【Android App】实战项目之仿抖音的短视频分享App(附源码和...
前言这一篇博客应该是我花时间最多的一次了,从2022年1月底至...
因为我既对接过session、cookie,也对接过JWT,今年因为工作...