Reputation: 22487
I know that I can check the type of a var in Swift with is
if item is Movie {
movieCount += 1
} else if item is Song {
songCount += 1
}
but how can I check that two instances have the same class? The following does not work:
if item1 is item2.dynamicType {
print("Same subclass")
} else {
print("Different subclass)
}
I could easily add a "class" function and update it in each subclass to return something unique, but that seems like a kludge...
Upvotes: 49
Views: 37675
Reputation: 453
In Swift 5 you can test whether one value is the same type as another, if one of the values is 'self', by using 'Self', its type. This works with structs, as you can see below.
(I am actually here looking for a way to do this without Self as I am trying to refactor something. The 'type(of: ship)' method mentioned above, looks like the most general way to do this. I have tested that it works with the example below.)
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.
Upvotes: 2
Reputation: 4908
For subclasses of NSObject
, I went with:
let sameClass: Bool = instance1.classForCoder == instance2.classForCoder
Another caveat of this method,
The private subclasses of a class cluster substitute the name of their public superclass when being archived.
Upvotes: 4
Reputation: 392
i'm using this, looks helpful for me:
it returns true
only if all objects are of same type;
func areObjects<T>(_ objects: [Any], ofType: T.Type) -> Bool {
for object in objects {
if !(object is T) {
return false
}
}
return true
}
Upvotes: 1
Reputation: 24041
I feel necessary to quote from the Swift Programming Language documentation first of all:
Classes have additional capabilities that structures do not:
- Type casting enables you to check and interpret the type of a class instance at runtime.
According to this, it may be helpful for someone in the future:
func areTheySiblings(class1: AnyObject!, class2: AnyObject!) -> Bool {
return object_getClassName(class1) == object_getClassName(class2)
}
and the tests:
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
you also can overload a new operator for doing such a thing, like e.g. this:
infix operator >!<
func >!< (object1: AnyObject!, object2: AnyObject!) -> Bool {
return (object_getClassName(object1) == object_getClassName(object2))
}
and the results:
println("Array vs Array: \(myArray1 >!< myArray2)") // true
println("Array vs. String: \(myArray1 >!< myString)") // false
println("Array vs. Dictionary: \(myArray1 >!< myDictionary)") // false
you can also use it for your own new Swift classes, like e.g. those:
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
Upvotes: 34
Reputation: 2591
Swift 3 - pay attention that comparing instances is not the same as checking if an istance is of a given type:
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
Upvotes: 12
Reputation: 6393
Swift 3.0 (also works with structs)
if type(of: someInstance) == type(of: anotherInstance) {
print("matching type")
} else {
print("something else")
}
Upvotes: 52
Reputation: 15615
I also answered How do you find out the type of an object (in Swift)? to point out that at some point Apple added support for the ===
operator to Swift Types, so the following will now work:
if item1.dynamicType === item2.dynamicType {
print("Same subclass")
} else {
print("Different subclass")
}
This works even without importing Foundation
, but note it will only work for classes, as structs
have no dynamic type.
Upvotes: 48
Reputation: 9418
At the moment Swift types have no introspection, so there is no builtin way to get the type of an instance. instance.className
works for Objc classes.
Upvotes: 0