Type Casting

Introduction

Welcome to lesson 5 of The Swift Fundamentals with Bob. You’ve learned a number of ! and ? since Lesson 1. These are language features that distinguish Swift from the rest, and you’ve got to know all, when, where, how, and, most importantly, why.

In this lesson, you learn how to convert types in objects that are created with classes and structs. In fact, if you use Storyboard in iOS, you must know type casting.

Problem

  1. How do you distinguish between as, as?, as!?
  2. Why does Xcode keep telling me what to do?

Type Casting in UIKit

You might have seen,

  1. import UIKit
  2. let label = UILabel() as UIView

You’ve converted UILabel to UIView. UILabel is a subclass of UIView. Let us attempt to replicate the phenomenon with custom classes.

The UIKit framework hierarchy

Human Class

Design a class called, Human that contains a single method.

  1. class Human {
  2. func introduce() {
  3. print("Hi, I'm a human")
  4. }
  5. }

Human Subclass

Design Korean and Japanese which inherit from the Human class.

  1. class Korean: Human {
  2. func singGangNamStyle() {
  3. print("Oppa Gangnam Style")
  4. }
  5. }
  6. class Japanese: Human {
  7. func doNinja() {
  8. print("Shhh.....")
  9. }
  10. }

Check if all good

  1. let bob = Korean()
  2. bob.introduce() // "Hi, I'm a human"
  3. bob.singGangNamStyle() // "Oppa Gangnam Style"

Type Casting

You may convert Korean to Human or vice versa. There are two ways: upcasting and downcasting.

Upcasting

Upcasting occurs when an object converts its type to the base class. In the early above, you’ve upcasted UILabel to UIView using as.

The word “up” aligns with the structure in the graph above.

  1. let newBob = bob as Human // Korean -> Human
  2. newBob.introduce()
  3. newBob.singGangNamStyle() // Does not exist

Upcasting Example in Swift Struct

  1. var name = "Bob" as Any
  2. var number = 20 as Any
  3. var anyArray = [name, number] // [Any]

I forgot to mention that Int and String are struct types which lack base classes. However, structs may only “upcast” to Any.

Downcasting

Downcasting is the opposite. You may downcast Any to String. However, it may fail since Any could contain many types. Analogous to optionals, there are two ways to downcast: Force downcasting or Implicit downcasting

Force Downcasting

It does not return an optional type. but if it fails, it crashes.

  1. // Force Downcasting
  2. let newValue = anyArray[0] as! String
  3. let newValue = anyArray[1] as! String // Error

Downcasting is only available only after upcasting.

Implicit Downcasting

It returns an optional type. If it fails, it returns nil.

  1. let newNewValue = anyArray[0] as? Int
  2. print(newNewValue) // Optional(20)

Type Casting in Practice

Create Instances

  1. let shion = Japanese()
  2. let lee = Korean()
  3. let kenji = Japanese()
  4. let park = Korean()

Create Array Using Upcasting

  1. let humans: [Human] = [shion as Human, lee as Human, kenji as Human, park as Human]

Automatic upcasting

  1. let humans: [Human] = [shion, lee, kenji, park]
  2. let humans = [shion, lee, kenji, park]

Loop

  1. for human in humans {
  2. if let korean = human as? Korean {
  3. korean.singGangNamStyle()
  4. }
  5. if let japanese = human as? Japanese {
  6. japanese.doNinja()
  7. }
  8. }

Usage in iOS Development

Typecasting can be used to group UI Components and add attributes as a whole.

  1. import UIKit
  2. let loginButton = UIButton()
  3. let loginMessage = UILabel()
  4. let loginView = UIView()
  5. let UIComponents = [loginButton, loginMessage, loginView]
  6. for component in UIComponents {
  7. if let button = component as? UIButton {
  8. // Change background color
  9. // Add Title
  10. // ...
  11. }
  12. if let label = component as? UILabel {}
  13. if let view = component as? UIView {}
  14. }

Important: Upcasting is not a recommended practice since there is a better way to go about: Protocol Oriented Programming. I mention drawbacks of using type casting through comparison in Chapter 3 and 5.

Another Example

To fetch a view controller from Storyboard, downcast to identify the designated view controller.

  1. let storyboard = UIStoryboard(name: "Main", bundle: nil)
  2. let vc = storyboard instantiateViewController(withIdentifier: "VC")
  3. // type of vc = UIViewController
  4. let vc = storyboard instantiateViewController(withIdentifier: "VC") as! VC
  5. // type of vc = VC

Source Code

1005_type_casting.playground

Reference

AnyObject and Any in Swift (Stack Overflow)

Conclusion

I lied. I said type casting allowed to convert types in classes. However, you may also convert Int and String to Any even though they are made up of structs, not classes.

Unnecessary type casting is not recommended among iOS developers because it causes a massive headache from casting back and forth. There is an alternative to go about. You will learn how to group objects together through Protocol Oriented Swift in Chapter 3. I know you are excited. Learn fast, but stay patient and consistent.

In the next lesson, you will learn how to design reusable code through generics. You will come out dry, not wet, a.k.a we enjoy typing.