How to Test If an Instance Is a Specific Class or Type in Swift

Checking if an object is a given type in Swift

If you want to check against a specific type you can do the following:

if let stringArray = obj as? [String] {
// obj is a string array. Do something with stringArray
}
else {
// obj is not a string array
}

You can use "as!" and that will throw a runtime error if obj is not of type [String]

let stringArray = obj as! [String]

You can also check one element at a time:

let items : [Any] = ["Hello", "World"]
for obj in items {
if let str = obj as? String {
// obj is a String. Do something with str
}
else {
// obj is not a String
}
}

Swift - check if two objects are of same type or superclass-type

One way could be to try generics like this

func isObject<P>(_ object: Any, ofType other: P) -> Bool {
object is P
}

isObject(myObject, ofType: myOtherObject) //true
isObject(mySubclassedObject, ofType: myObject) //true
isObject(myObject, ofType: mySubclassedObject) //false

Swift - check if instance is one of multiple types

You can use type(of:) and .contains:

let types = [A.self, C.self]

let test = A()

if types.contains(where: { $0 == type(of:test) }) {
print("Here")
}

Can you check if a Type (not an instance) is a subclass of another Type?

To expand upon Martin R's great answer you can make an array extension like the following:

extension Array {
func first<T>(ofType: T.Type) -> T.Type? {
return first { $0 is T.Type } as? T.Type
}
func first<T>(ofExactType type: T.Type) -> T.Type? {
return first { $0 as? Any.Type == type } as? T.Type
}
}

class Vehicle {}
class Car : Vehicle {}
class Honda: Car {}

let carTypes = [Honda.self, Vehicle.self, Car.self] // Inferred type [Vehicle]
print(carTypes.first(ofType: Car.self) ?? "n/a") // prints Honda
print(carTypes.first(ofExactType: Car.self) ?? "n/a") // prints Car

Also, just FYI, $0 as? Any.Type == type is the same as doing $0 as? Any.Type == T.self. Either one would work.

How to check if a UIViewController is of a particular sub-class in objective c?

The isKindOfClass: method indicates whether an object is an instance of given class or an instance of a subclass of that class.

if ([instance1 isKindOfClass:[CustomUIViewController class]]) {
// code
}

If you want to check whether an object is an instance of a given class (but not an instance of a subclass of that class), use isMemberOfClass: instead.

How can I tell what the class of an instance variable is in Swift

Use type.self to return a type that can be passed into a method that accepts a type-level argument. For example, UILabel.self can be passed to the isKindOfClass method call. The string representation of the class can be found via dynamicType.description():

var label = UILabel()
println(label.dynamicType.description())
println(label.isKindOfClass(UILabel.self))

Swift-3

var label = UILabel()
println(type(of: label).description())

Output
UILabel
true

Here's a bit more background -- there are two expressions to be aware of: the postfix self expression and the dynamic type expression. From the docs:

Postfix Self
A postfix self expression consists of an expression or the name of a
type, immediately followed by .self. It has the following forms:

expression.self
type.self

The first form evaluates to the value of the expression. For example,
x.self evaluates to x.

The second form evaluates to the value of the type. Use this form to
access a type as a value. For example, because SomeClass.self
evaluates to the SomeClass type itself, you can pass it to a function
or method that accepts a type-level argument



Dyamic Type Expression

A dynamicType expression consists of an expression, immediately
followed by .dynamicType. It has the following form:

expression.dynamicType

The expression can’t be the name of a type. The entire dynamicType
expression evaluates to the value of the runtime type of the
expression.

Testing type for class conformance in Swift

As Martin notes in a comment, any value can be cast to AnyObject in Swift, because Swift will wrap value types in an opaque _SwiftValue class, and the cast will always succeed. There is a way around this, though.

The way to check whether a value is a reference type without this implicit casting is to check whether its type is AnyObject.Type, like so:

func printIsObject(_ value: Any) {
if type(of: value) is AnyObject.Type {
print("Object")
} else {
print("Other")
}
}

class Foo {}
struct Bar {}
enum Quux { case q }

printIsObject(Foo()) // => Object
printIsObject(Bar()) // => Other
printIsObject(Quux.q) // => Other

Note that it's crucial that you check whether the type is AnyObject.Type not is AnyObject. T.self, the object representing the type of the value, is itself an object, so is AnyObject will always succeed. Instead, is AnyObject.Type asks "does this inherit from the metatype of all objects", i.e., "does this object which represents a type inherit from an object that represents all object types?"


Edit: Evidently, I'd forgotten that Swift includes AnyClass as a synonym for AnyObject.Type, so the check can be simplified to be is AnyClass. However, leaving the above as a marginally-expanded explanation for how this works.


If you want this method to also be able to handle Optional values, you're going to have to do a bit of special-casing to add support. Specifically, because Optional<T> is an enum regardless of the type of T, you're going to need to reach in to figure out what T is.

There are a few ways to do this, but because Optional is a generic type, and it's not possible to ask "is this value an Optional<T>?" without knowing what T is up-front, one of the easier and more robust ways to do this is to introduce a protocol which Optional adopts that erases the type of the underlying value while still giving you access to it:

protocol OptionalProto {
var wrappedValue: Any? { get }
}

extension Optional: OptionalProto {
var wrappedValue: Any? {
switch self {
case .none: return nil
case let .some(value):
// Recursively reach in to grab nested optionals as needed.
if let innerOptional = value as? OptionalProto {
return innerOptional.wrappedValue
} else {
return value
}
}
}
}

We can then use this protocol to our advantage in cache:

func cache(id: Int, instance: Any) {
if let opt = instance as? OptionalProto {
if let wrappedValue = opt.wrappedValue {
cache(id: id, instance: wrappedValue)
}

return
}

// In production:
// cache[id] = WeakBox(boxed: instance as AnyObject)

if type(of: instance) is AnyClass {
print("\(type(of: instance)) is AnyClass")
} else {
print("\(type(of: instance)) is something else")
}
}

This approach handles all of the previous cases, but also infinitely-deeply-nested Optionals, and protocol types inside of Optionals:

class Foo {}
struct Bar {}
enum Quux { case q }

cache(id: 1, instance: Foo()) // => Foo is AnyClass
cache(id: 2, instance: Bar()) // => Bar is something else
cache(id: 3, instance: Quux.q) // => Quux is something else

let f: Optional<Foo> = Foo()
cache(id: 4, instance: f) // => Foo is AnyClass

protocol SomeProto {}
extension Foo: SomeProto {}

let p: Optional<SomeProto> = Foo()
cache(id: 5, instance: p) // => Foo is AnyClass

How to check two instances are the same class/type in swift

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

UPDATE

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

UPDATE#2

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


Related Topics



Leave a reply



Submit