Swift Type Casting – as, is, Any, AnyObject

Filed Under: Swift
Swift Type Casting - Any AnyObject

In this tutorial, we’ll be looking into the details of Swift Type Casting. Let’s get started on our Xcode Playground!

What is Swift Type Casting?

Broadly, Type Casting consists of two things:

  • Type Checking
  • Changing the Type
  • is operator is used to check the type of an instance.
  • as operator is used to cast the instance to another type.

Swift Type Checking

Swift gives a lot of priority to the readability of the code. No wonder to check whether an instance belongs to a certain type, we use the is keyword.

For Example, the following code snippet would always print false.


var isString = Int.self is String 
print(isString) // false

Let’s do the type checking in the class and its subclasses. For that, we’ve created the following three classes.


class University
{
    var university: String
    init(university: String) {
        self.university = university
    }
}

class Discipline : University{
    var discipline: String
    init(university: String, discipline: String) {
        self.discipline = discipline
        super.init(university: university)
    }
}

class Student : University{
    var student: String
    init(student: String, university: String) {
        self.student = student
        super.init(university: university)
    }
}

In the following sections, we’ll be looking at Upcasting and Downcasting.

Swift Upcasting

Let’s create an object of each of the classes and combine them in an Array. Our goal is to know thy type!


var array = [University(university: "MIT"),Discipline(university: "IIT",discipline: "Computer Science"),Student(student: "Anupam",university: "BITS")]

print(array is [Student])
print(array is [Discipline])
print(array is [University])

The following output is printed.
Swift Type Casting - Upcasting

The array is of the type University. All the subclasses are always implicitly upcasted to the parent class.

In the above code, the Swift Type Checker automatically determines the common superclass of the classes and sets the type to it.

type(of:) can be used to determine the type of any variable/constant.


var university = University(university: "MIT")
var student = Student(student: "Anupam",university: "BITS")
var discipline = Discipline(university: "IIT",discipline: "Computer Science")

print(student is University) //true
print(discipline is University) //true
print(university is Student) //false
print(university is Discipline) //false

Protocols are types. Hence type checking and casting works the same way on them.

The following code prints true.


protocol SomeProtocol {
    init(str: String)
    
}

class SomeClass : SomeProtocol {
    required init(str: String) {
    }
}

var sc = SomeClass(str: "JournalDev.com")
print(sc is SomeProtocol) //true

Swift Downcasting

For downcasting a superclass to the subclass, we use the operator as.

  1. as has two variants, as? and as! to handle scenarios when the downcasting fails.
  2. as is typically used for basic conversions.
  3. as? would return an optional value if the downcast succeeds and nil when it doesn’t.
  4. as! force unwraps the value. Should be used only when you’re absolutely sure that the downcast won’t fail. Otherwise, it’ll lead to a runtime crash.

//Double to float
let floatValue = 2.35661312312312 as Float
print(float) //prints 2.35661

let compilerError = 0.0 as Int //compiler error
let crashes = 0.0 as! Int //runtime crash

Let’s look at the class hierarchy again. Let’s try to downcast the array elements to the subclass types now.


var array = [University(university: "MIT"),
             Discipline(university: "IIT",discipline: "Computer Science"),
             Student(student: "Anupam",university: "BITS"),
             Student(student: "Mark",university: "MIT")]

for item in array {
    if let obj = item as? Student {
        print("Students Detail: \(obj.student), \(obj.university)")
    } else if let obj = item as? Discipline {
        print("Discipline Details: \(obj.discipline), \(obj.university)")
    }
}

We downcast the type University to the subclass types.
Following results get printed in the console.
Swift Type Casting - Downcasting

We’ve used if let statements to unwrap the optionals gracefully.

Any and AnyObject

As per the Apple Docs:

Any can represent an instance of any type at all, including function types.
AnyObject can represent an instance of any class type.

AnyObject can be a part of Any type.
Inside an AnyObject array, to set value types, we need to typecast them to the AnyObject using as operator.


class A{
    var a = "Anupam"
}
func hello()
{
    print("Hello")
}

var anyType : [Any] = [1, "Hey",array,true, 1.25, A(), hello()]
var anyObjectType : [AnyObject] = [A(),array as AnyObject, 1 as AnyObject,"Hey" as AnyObject]

print(anyType)
print(anyObjectType)

for item in anyType {
    if let obj = item as? A {
        print("Class A property name is: \(obj.a)")
    }
}

for item in anyObjectType {
        if let obj = item as? String {
            print("String type: \(type(of: obj))")
        }
}

Swift Type Casting - Any AnyObject

The function that’s present in the anyType array, gets printed on the array’s declaration.

Notice that for anyObjectType, the string gets printed without double quotes.

Besides AnyObject allows object types only. String and Int are value types.

Then how is it working?.

On typecasting the string and int as AnyObject they both get converted into NSString and NSNumber class types which are not value types. Hence it is possible to set String, Int in AnyObject provided we use the as operator correctly.

That’s all for swift type casting.

Reference: Apple Docs

Leave a Reply

Your email address will not be published. Required fields are marked *

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages