【问题标题】:How to check two instances are the same class/type in swift如何在swift中检查两个实例是否相同的类/类型
【发布时间】:2014-06-11 11:19:22
【问题描述】:

我知道我可以在 Swift 中使用 is 来检查 var 的类型

if item is Movie {
    movieCount += 1
} else if item is Song {
    songCount += 1
}

但是如何检查两个实例是否具有相同的类?以下方法不起作用:

if item1 is item2.dynamicType {
    print("Same subclass")
} else {
    print("Different subclass)
}

我可以很容易地添加一个“类”函数并在每个子类中更新它以返回一些独特的东西,但这看起来像是一个杂物......

【问题讨论】:

  • 在 Swift 中通常不需要这样的比较。
  • 嗯,我在示例中使用“子类”而不是“类”的原因是线索 - 有几个通常被类似对待的交互子类是很常见的,但是当它们被处理时会做一些特殊的事情相同 - 例如 Animal 的子类,它们与所有其他子类交互(例如,远离)所有其他子类,但不是它们自己的......
  • 不,如果你检查两个类都是Animal,你通常不会检查它们的类是否相同。如果您有具有相同接口的不同类(它们可以相互交互),但在某些情况下您不希望它们相互交互,那么您的设计就存在严重问题。
  • 如果您仍然对AnyObject 的纯 Swift 解决方案持开放态度,请查看我的回答。
  • 非常好 - 非常感谢!我已将接受的答案更改为您的答案。

标签: swift


【解决方案1】:

我还回复了How do you find out the type of an object (in Swift)?,指出 Apple 在某些时候向 Swift 类型添加了对 === 运算符的支持,因此现在可以使用以下方法:

if item1.dynamicType === item2.dynamicType {
    print("Same subclass")
} else {
    print("Different subclass")
}

即使不导入 Foundation 也可以使用,但请注意它仅适用于类,因为 structs 没有动态类型。

【讨论】:

  • 此答案中的代码不再使用 Swift 2.0 进行编译
  • @ndmeiri 有趣!看起来编译器非常聪明,并且发现这些类型不能相同。如果您首先分配给变量,它会起作用:let item1 = UIColor(), item2 = UIFont(); if item1.dynamicType === item2.dynamicType { 此外,您可以执行item1.dynamicType === UIColor.self 之类的操作来检查已知类(请注意,UIColor() 确实 not 返回 @ 的直接实例987654329@,所以结果是false)
  • dynamicType 已被弃用。改用type(of: ...)
  • @T.本杰明拉森的回答对 Swift 4 是正确的。
  • 可爱的:'.dynamicType' 已被弃用。改用'type(of: ...)'
【解决方案2】:

Swift 3.0(也适用于结构)

if type(of: someInstance) == type(of: anotherInstance) {
    print("matching type")
} else {
    print("something else")
}

【讨论】:

  • 这对我不起作用。 var type = type(of: visibleController as!ContactsBaseVC) var type2 = type(of: self as!ContactsBaseVC) if type(of: self) == type(of: visibleController){ print("Add Contact Presed") }
  • 在没有更多上下文的情况下破译问题有点困难,但如果这些控制器中的任何一个被向下转换为 ContactBaseVC 类型,则底层类型仍然是原始类型,不是那个你很沮丧的人。
【解决方案3】:

我觉得有必要首先引用 Swift Programming Language 文档:

类具有结构没有的额外功能:

  • 类型转换使您能够在运行时检查和解释类实例的类型。

据此,将来可能对某人有所帮助:

func areTheySiblings(class1: AnyObject!, class2: AnyObject!) -> Bool {
    return object_getClassName(class1) == object_getClassName(class2)
}

和测试:

let myArray1: Array<AnyObject> = Array()
let myArray2: Array<Int> = Array()
let myDictionary: Dictionary<String, Int> = Dictionary()
let myString: String = String()

let arrayAndArray: Bool = self.areTheySiblings(myArray1, class2: myArray2) // true
let arrayAndString: Bool = self.areTheySiblings(myArray1, class2: myString) // false
let arrayAndDictionary: Bool = self.areTheySiblings(myArray1, class2: myDictionary) // false

更新

你也可以重载一个新的操作符来做这样的事情,比如这个:

infix operator >!<

func >!< (object1: AnyObject!, object2: AnyObject!) -> Bool {
   return (object_getClassName(object1) == object_getClassName(object2))
}

结果:

println("Array vs Array: \(myArray1 >!< myArray2)") // true
println("Array vs. String: \(myArray1 >!< myString)") // false
println("Array vs. Dictionary: \(myArray1 >!< myDictionary)") // false

更新#2

您也可以将它用于您自己的新 Swift 类,例如那些:

class A { }
class B { }

let a1 = A(), a2 = A(), b = B()

println("a1 vs. a2: \(a1 >!< a2)") // true
println("a1 vs. b: \(a1 >!< b)") // false

【讨论】:

  • 完美!那会做得很好!
  • 这实际上不是“纯 Swift”,因为 object_getClassName 是一个 ObjC 运行时函数。 (因此,它不适用于无法桥接到 ObjC 类的 Swift 类型。)
  • 该函数来自于 Objective-C 运行时,所以它在 Swift 中不可用,除非你 import Foundation(或 import Cocoaimport UIKit)。它不适用于非 ObjC Swift 类型。这是一个很好的解决方案……只是试图降低期望。
  • 并非所有 Swift 类型都可以桥接到 ObjC 对象,即使它们在其他方面表现得像对象。测试:struct S {}; let a = S(); println(object_getClassName(a)) 您可以在“纯”Swift 中进行大量有用的开发——即使您的 UI 代码需要使用 Cocoa 框架,在不导入任何内容的文件中包含模型类也是完全合理的。我从来没有说过你的解决方案不能广泛适用,只是读者不应该期望它是通用的。
  • 屈尊俯就并不适合 SO。您是否运行了我之前评论中的测试代码?
【解决方案4】:

斯威夫特 3 - 请注意,比较实例与检查一个 istance 是否属于给定类型是不同的:

struct Model {}

let modelLhs = Model()
let modelRhs = Model()
type(of: modelLhs) == type(of: modelRhs) //true
type(of: modelLhs) == type(of: Model.self) //false
modelLhs is Model //true

【讨论】:

    【解决方案5】:

    对于NSObject 的子类,我选择了:

    let sameClass: Bool = instance1.classForCoder == instance2.classForCoder
    

    此方法的另一个警告,

    类簇的私有子类在归档时替换其公共超类的名称。

    Apple documentation

    【讨论】:

    • 出于某种原因,这是唯一适用于 ViewControllers 的东西,其他人总是返回 UIViewController 类而不是从它继承的类
    【解决方案6】:

    我正在使用这个,看起来对我很有帮助: 仅当所有对象都属于同一类型时,它才会返回 true

    func areObjects<T>(_ objects: [Any], ofType: T.Type) -> Bool {
        for object in objects {
            if !(object is T) {
                return false
            }
        }
        return true
    }
    

    【讨论】:

      【解决方案7】:

      在 Swift 5 中,您可以测试一个值是否与另一个值相同,如果其中一个值是“self”,则可以使用它的类型“Self”。这适用于结构,如下所示。

      (我实际上是在这里寻找一种没有 Self 的方法,因为我正在尝试重构某些东西。上面提到的 'type(of:ship)' 方法看起来是最通用的方法。我有测试它是否适用于下面的示例。)

      protocol Ship { var name: String {get} }
      
      extension Ship {
          func isSameClass(as other: Ship) -> Bool {
              return other is Self
          }
      }
      
      struct Firefly: Ship { var name: String }
      struct Trebuchet: Ship { var name: String }
      
      func speak(about s1: Ship, and s2: Ship) {
          print(  "\(s1.name) and \(s2.name) are "
              +   "\(s1.isSameClass(as: s2) ? "" : "not ")"
              +   "the same class." )
      }
      
      func talk(about s1: Ship, and s2: Ship) {
          print(  "\(s1.name) and \(s2.name) are "
              +   "\(type(of: s1) == type(of: s2) ? "" : "not ")"
              +   "the same class." )
      }
      
      var serenity = Firefly(name: "Serenity")
      var saffron = Firefly(name: "Saffron")
      var inara = Trebuchet(name: "Inara")
      
      speak(about: serenity, and: saffron)    // Serenity and Saffron are the same class.
      speak(about: serenity, and: inara)      // Serenity and Inara are not the same class.
      talk(about: serenity, and: saffron)     // Serenity and Saffron are the same class.
      talk(about: serenity, and: inara)       // Serenity and Inara are not the same class.
      

      【讨论】:

        【解决方案8】:

        目前 Swift 类型没有自省,所以没有内置的方法来获取实例的类型。 instance.className 适用于 Objc 类。

        【讨论】:

        • 我不同意,有办法检查AnyObject的类。
        猜你喜欢
        • 2021-03-06
        • 1970-01-01
        • 1970-01-01
        • 2016-12-31
        • 1970-01-01
        • 2011-05-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多