iOS: Beginner’s Guide — UIKit (3/3)

If you haven’t checked out Day 2 in the journey, you can check that out right here.

Polymorphism and Typecasting

The concept of polymorphism is that any instance of a subclass is inherited from its superclass can be treated just as either a subclass or its superclass — it’s essentially the both at the same time.

In short, an object can represent both as its class and its superclass in the same time.

An example of polymorphism

Typecasting

Typecasting is when you are converting an object from one type to another.

There are 3 types, but you will more commonly encounter these two:

To be specific, typecasting doesn’t actually transform anything, and it just converts how Swift treats the object (more like an interpretation). You are informing Swift that an object it believed was type A was actually type B.

An example of optional downcasting

Optional downcasting is most often used with if let statements to safely unwrap the optional at the same time while downcasting or changing the instance or object’s “interpretation”.

An example of forced downcasting

Alternatively, you can do the following as well, which would be more efficient:

An example of forced downcasting

You can also apply optional downcasting at the array level, but it’s a bit tricky because you need to utilize the nil coalescing operator to guarantee that there is a value for the loop.

An example of optional downcasting

You cannot force to convert something to a completely different, unrelated type. Typecasting is only useful when you know something that Swift does not.

Closures

Closures can be interpreted as variables, or more specifically lines that contain code.

NOTE: Closures take a copy of the values that are used inside them (capture the environment where they are created).

UIView is an iOS data type within UIKit that is the most basic type of UI container, and UIView has a method called animate() that manipulates the interface utilizing animations by describing what exactly is changing and over how many seconds the animation is taking place.

An example of UIView’s animate method

Within the closure, what happens is that UIKit takes a copy of the code within the braces, stores it, makes the necessary preparations, and then runs the code when it is ready. Closures capture their environment as the uiView instance is declared outside of the closure, we have access to that instance within the closure.

NOTE: If object A stores a closure as a property and that same property also references object A, then this is called a strong reference cycle.

For trailing closures, the rule is that if the last parameter to a method contains a closure, then you can delete that parameter and replace it with a block of code within braces outside of the parentheses.

An example of a trailing closure

Protocols

Protocols are Swift contracts where you define a set of properties and methods that a type must implement if it conforms to a protocol.

An example of a protocol

There are 3 important things to note with the example above:

An example of a protocol used in action

NOTE: We can create an ExampleProtocol array and use instances or objects within that array without knowing what their actual type is (as long as the instances or objects conform to the protocol defined by the array).

Extensions

Extensions allow us to modify Swift’s data types to add new functionality.

An example of an extension

NOTE: The extension multiplies 2 to its input number and returns it to the caller but does not modify its original value.

An example of using the mutating keyword

Swift forces you to use the mutating keyword to indicate that it will change its input, and because the function no longer returns a value, in this case, we use *= to multiply 2 to self.

If you declare a method as being mutating, you cannot use it with constants as Swift knows that it will be changing values.

Extensions are similar to subclasses, but the main reason why the former is used over the latter is because of its extensibility. Extensions are applicable to all data types, and they do not conflict when you have more than one.

Conventionally, we name our extension files as Type + Modifier + .swift

Protocol Extensions

Whereas protocols define contracts that conforming types must adopt, protocol extensions allow us to define how things within the protocol must execute, adding the necessary functionality to all types that conform to the protocol within a single place.

An example of an extension

There are other types of Int in Swift such as:

Therefore, if we just specify the constant Int as conforming to the Int specific data type, then this code above would not affect other varieties of integers like UInt, Int8, and UInt64 so our solution is using protocol extensions that allow us to modify several data types at once.

There is an important distinction to make:

An example of using Self

We redefined our extension as applying to BinaryInteger rather than Int because BinaryInteger is a protocol that all of Swift’s integer types conforms to, meaning that all of the integer types now have access to the number method above (which makes it easier so we don’t have to extend each one individually).

An example of a protocol extension

We implement a default method so the types that conform to the protocol do not need to implement the required method themselves unless if they want to (in this case, all conforming types automatically get a workingHard() method defined and implemented by default).

--

--

iOS Developer | Full Stack Developer | Software Engineer | LinkedIn: john-kim-developer | GitHub: cloudiosx | Portfolio: cloudiosx.com

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
John Kim

iOS Developer | Full Stack Developer | Software Engineer | LinkedIn: john-kim-developer | GitHub: cloudiosx | Portfolio: cloudiosx.com