Checking if an object is a given type in Swift

SwiftType InferenceTypechecking

Swift Problem Overview


I have an array that is made up of AnyObject. I want to iterate over it, and find all elements that are array instances.

How can I check if an object is of a given type in Swift?

Swift Solutions


Solution 1 - 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
   }
}

Solution 2 - Swift

In Swift 2.2 - 5 you can now do:

if object is String
{
}

Then to filter your array:

let filteredArray = originalArray.filter({ $0 is Array })

If you have multiple types to check:

    switch object
    {
    case is String:
        ...

    case is OtherClass:
        ...

    default:
        ...
    }

Solution 3 - Swift

If you only want to know if an object is a subtype of a given type then there is a simpler approach:

class Shape {}
class Circle : Shape {}
class Rectangle : Shape {}

func area (shape: Shape) -> Double {
  if shape is Circle { ... }
  else if shape is Rectangle { ... }
}

“Use the type check operator (is) to check whether an instance is of a certain subclass type. The type check operator returns true if the instance is of that subclass type and false if it is not.” Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks.

In the above the phrase 'of a certain subclass type' is important. The use of is Circle and is Rectangle is accepted by the compiler because that value shape is declared as Shape (a superclass of Circle and Rectangle).

If you are using primitive types, the superclass would be Any. Here is an example:

 21> func test (obj:Any) -> String {
 22.     if obj is Int { return "Int" }
 23.     else if obj is String { return "String" }
 24.     else { return "Any" }
 25. } 
 ...  
 30> test (1)
$R16: String = "Int"
 31> test ("abc")
$R17: String = "String"
 32> test (nil)
$R18: String = "Any"
 

Solution 4 - Swift

I have 2 ways of doing it:

if let thisShape = aShape as? Square 

Or:

aShape.isKindOfClass(Square)

Here is a detailed example:

class Shape { }
class Square: Shape { } 
class Circle: Shape { }

var aShape = Shape()
aShape = Square()

if let thisShape = aShape as? Square {
    println("Its a square")
} else {
    println("Its not a square")
}

if aShape.isKindOfClass(Square) {
    println("Its a square")
} else {
    println("Its not a square")
}

Edit: 3 now:

let myShape = Shape()
if myShape is Shape {
    print("yes it is")
}

Solution 5 - Swift

for swift4:

if obj is MyClass{
    // then object type is MyClass Type
}

Solution 6 - Swift

Assume drawTriangle is an instance of UIView.To check whether drawTriangle is of type UITableView:

In Swift 3,

if drawTriangle is UITableView{
    // in deed drawTriangle is UIView
    // do something here...
} else{
    // do something here...
}

This also could be used for classes defined by yourself. You could use this to check subviews of a view.

Solution 7 - Swift

Why not use the built in functionality built especially for this task?

let myArray: [Any] = ["easy", "as", "that"]
let type = type(of: myArray)

Result: "Array<Any>"

Solution 8 - Swift

Be warned about this:

var string = "Hello" as NSString
var obj1:AnyObject = string
var obj2:NSObject = string

print(obj1 is NSString)
print(obj2 is NSString)
print(obj1 is String)
print(obj2 is String) 

All of the four last lines return true, this is because if you type

var r1:CGRect = CGRect()
print(r1 is String)

... it prints "false" of course, but a Warning says that the Cast from CGRect to String fails. So some type are bridged, ans the 'is' keyword calls an implicit cast.

You should better use one of these:

myObject.isKind(of: MyClass.self)) 
myObject.isMember(of: MyClass.self))

Solution 9 - Swift

Just for the sake of completeness based on the accepted answer and some others:

let items : [Any] = ["Hello", "World", 1]

for obj in items where obj is String {
   // obj is a String. Do something with str
}

But you can also (compactMap also "maps" the values which filter doesn't):

items.compactMap { $0 as? String }.forEach{ /* do something with $0 */ ) }

And a version using switch:

for obj in items {
    switch (obj) {
        case is Int:
           // it's an integer
        case let stringObj as String:
           // you can do something with stringObj which is a String
        default:
           print("\(type(of: obj))") // get the type
    }
}

But sticking to the question, to check if it's an array (i.e. [String]):

let items : [Any] = ["Hello", "World", 1, ["Hello", "World", "of", "Arrays"]]

for obj in items {
  if let stringArray = obj as? [String] {
    print("\(stringArray)")
  }
}

Or more generally (see this other question answer):

for obj in items {
  if obj is [Any] {
    print("is [Any]")
  }

  if obj is [AnyObject] {
    print("is [AnyObject]")
  }

  if obj is NSArray {
    print("is NSArray")
  }
}

Solution 10 - Swift

as? won't always give you the expected result because as doesn't test if a data type is of a specific kind but only if a data type can be converted to or represented as specific kind.

Consider this code for example:

func handleError ( error: Error ) {
    if let nsError = error as? NSError {

Every data type conforming to the Error protocol can be converted to a NSError object, so this will always succeed. Yet that doesn't mean that error is in fact a NSError object or a subclass of it.

A correct type check would be:

func handleError ( error: Error ) {
    if type(of: error) == NSError.self {

However, this checks for the exact type only. If you want to also include subclasses of NSError, you should use:

func handleError ( error: Error ) {
    if error is NSError.Type {

Solution 11 - Swift

If you just want to check the class without getting a warning because of the unused defined value (let someVariable ...), you can simply replace the let stuff with a boolean:

if (yourObject as? ClassToCompareWith) != nil {
   // do what you have to do
}
else {
   // do something else
}

Xcode proposed this when I used the let way and didn't use the defined value.

Solution 12 - Swift

Why not to use something like this

fileprivate enum types {
    case typeString
    case typeInt
    case typeDouble
    case typeUnknown
}

fileprivate func typeOfAny(variable: Any) -> types {
    if variable is String {return types.typeString}
    if variable is Int {return types.typeInt}
    if variable is Double {return types.typeDouble}
    return types.typeUnknown
}

in Swift 3.

Solution 13 - Swift

Swift 4.2 , In my case , using isKind function .

> isKind(of:) Returns a Boolean value that indicates whether the receiver is an instance of given class or an instance of any class that inherits from that class.

  let items : [AnyObject] = ["A", "B" , ... ]
  for obj in items {
    if(obj.isKind(of: NSString.self)){
      print("String")
    }
  }

Readmore https://developer.apple.com/documentation/objectivec/nsobjectprotocol/1418511-iskind

Solution 14 - Swift

myObject as? String returns nil if myObject is not a String. Otherwise, it returns a String?, so you can access the string itself with myObject!, or cast it with myObject! as String safely.

Solution 15 - Swift

Swift 3:

class Shape {}
class Circle : Shape {}
class Rectangle : Shape {}

if aShape.isKind(of: Circle.self) {
}

Solution 16 - Swift

If you have Response Like This:

{
  "registeration_method": "email",
  "is_stucked": true,
  "individual": {
    "id": 24099,
    "first_name": "ahmad",
    "last_name": "zozoz",
    "email": null,
    "mobile_number": null,
    "confirmed": false,
    "avatar": "http://abc-abc-xyz.amazonaws.com/images/placeholder-profile.png",
    "doctor_request_status": 0
  },
  "max_number_of_confirmation_trials": 4,
  "max_number_of_invalid_confirmation_trials": 12
}

and you want to check for value is_stucked which will be read as AnyObject, all you have to do is this

if let isStucked = response["is_stucked"] as? Bool{
  if isStucked{
      print("is Stucked")
  }
  else{
      print("Not Stucked")
 }
}

Solution 17 - Swift

If you don't know that you will get an array of dictionaries or single dictionary in the response from server you need to check whether the result contains an array or not.
In my case always receiving an array of dictionaries except once. So, to handle that I used the below code for swift 3.

if let str = strDict["item"] as? Array<Any>

Here as? Array checks whether the obtained value is array (of dictionary items). In else case you can handle if it is single dictionary item which is not kept inside an array.

Solution 18 - Swift

Swift 5.2 & Xcode Version:11.3.1(11C504)

Here is my solution of checking data type:

 if let typeCheck = myResult as? [String : Any] {
        print("It's Dictionary.")
    } else { 
        print("It's not Dictionary.") 
    }

I hope it will help you.

Solution 19 - Swift

let originalArray : [Any?] = ["Hello", "World", 111, 2, nil, 3.34]
let strings = originalArray.compactMap({ $0 as? String })

print(strings)
//printed: ["Hello", "World"]

Solution 20 - Swift

You can use this function and then call it

 func printInfo(_ value: Any) {
        let t = type(of: value)
        print("'\(value)' of type '\(t)'")
    }

such as printInfo(data) '125 bytes' of type 'Data'

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionEncore PTLView Question on Stackoverflow
Solution 1 - SwiftdrewagView Answer on Stackoverflow
Solution 2 - Swiftmeaning-mattersView Answer on Stackoverflow
Solution 3 - SwiftGoZonerView Answer on Stackoverflow
Solution 4 - SwiftEsqarrouthView Answer on Stackoverflow
Solution 5 - SwiftAhmad LabeebView Answer on Stackoverflow
Solution 6 - SwiftYushan ZHANGView Answer on Stackoverflow
Solution 7 - SwiftPatrik ForsbergView Answer on Stackoverflow
Solution 8 - SwifttontonCDView Answer on Stackoverflow
Solution 9 - SwiftFranMowinckelView Answer on Stackoverflow
Solution 10 - SwiftMeckiView Answer on Stackoverflow
Solution 11 - Swiftthe_marioooView Answer on Stackoverflow
Solution 12 - SwiftDawyView Answer on Stackoverflow
Solution 13 - SwiftTung TranView Answer on Stackoverflow
Solution 14 - SwiftcprcrackView Answer on Stackoverflow
Solution 15 - SwiftElijahView Answer on Stackoverflow
Solution 16 - SwiftAtefView Answer on Stackoverflow
Solution 17 - SwiftV.SView Answer on Stackoverflow
Solution 18 - SwiftSpencer ReidView Answer on Stackoverflow
Solution 19 - SwiftAnton N.View Answer on Stackoverflow
Solution 20 - SwiftACDA100View Answer on Stackoverflow