How to use Generics in iOS swift

Generics are an interesting concept, and they permit you to reuse your code for several types. Let’s stare at an example:

func swapInts(_ a: inout Int, _ b: inout Int) {

    let temporaryB = b

    b = a

    a = temporaryB

}

swapInts function obtains 2 Ints and swaps them. Here is a sample usage:

var num1 = 10

var num2 = 20

swapInts(&num1, &num2)

print(num1)   // 20

print(num2)   // 10

But what if we want to swap strings? Probably you will write another function like this:

func swapStrings(_ a: inout String, _ b: inout String) {

    let temporaryB = b

    b = a

    a = temporaryB

}

As you can observe, both functions are the same, except for the fact that they have different parameter types. We can concern Generics to write more flexible code. We can twist the swap function into a more generic function like this:

func swapAnything<T>(_ a: inout T, _ b: inout T) {

    let temporaryB = b

    b = a

    a = temporaryB

}

Here I will illustrate what we just wrote. We initiated by declaring what displays just like a normal swift function,

Let me explain what we just wrote. We started by declaring what looks just like a normal Swift function, however, as you can observe, we have the letter T in between angle brackets. What does this mean? Angle brackets are Swift’s syntax for generics. By placing the letter T in between angle brackets, we were explaining Swift that we are outlining a generic type, called T. Now we can mention this type T in our function. As you can observe, we use it to indicate the types of our parameters. Other function is just basic declarations. We can now use our swap anything functions to swap anything we need.

var string1 = "Happy"

var string2 = "New Year"

 

swapAnything(&string1, &string2)

print(string1) // New Year

print(string2) // Happy

 

var bool1 = false

var bool2 = true

 

swapAnything(&bool1, &bool2)

print(bool1) // true

print(bool2) // false

Let’s stare at a more complicated example of using generics. But first, let’s look back. For those of you who are well-known with Objective C, remember how items accessed from an NSArray would be returned as id? If we write this:

NSArray *myArray = @[1, 2, 3, 4, 5];

int myInt = (int)myArray[2];

Constantly, we would have to cast elements from the array into their actual types manually. This is insecure. What type of items are in the array? What type would you cast it to? What if you forget to cast it and you challenge to use the object anyway? Your app may crash because of an undefined selector or related concern.

This is the reason that Swift’s Generics come to rescue. Let’s take a look at the following example:

struct Stack {

    private var storage = [Any]()

    

    mutating func push(_ item: Any) {

        storage.append(item)

    }

    

    mutating func pop() -> Any? {

        return storage.removeLast()

    }

}

 

var myStack = Stack()

myStack.push("foo")

myStack.push(5)

myStack.push(4.7)

 

let element = myStack.pop()

Here, we declare a stack that permits you to push any items to it, and pop an item off.

Here the following issue. The item stock up in the stack, and the element we pop, is of type Any. How we know the element type? The right answer is…we don’t know. It might be a String, an Int, or a Float.

What can we do, if we have no idea about the items in the stack? All the time when you require using element, you will probably require finding its type like this:

switch element {

case let number as Int: print(number)

case let number as Double: print(number)

case let text as String: print(text)

default: print("Unknown type")

}

It doesn’t look like a good solution, and it is not a good practice to store items in an array of any type in Swift. A superior way to do it is to limit the stack to a single type. Here, we will have to build a stack for String, another for Int, another for String. And here, generics in Swift will permit you to build a generic stack:

struct GenericStack<Element> {

    private var storage = [Element]()

    

    mutating func push(_ item: Element) {

        storage.append(item)

    }

    

    mutating func pop() -> Element? {

        return storage.removeLast()

    }

}

It isn’t much more composite than our unique stack, but the stack is now type safe. Let’s observe it in action:

var textStack = GenericStack<String>()

textStack.push("foo")

textStack.push("bar")

textStack.push("baz")

 

let textElement = textStack.pop()  // baz

 

var numStack = GenericStack<Int>()

numStack.push(10)

numStack.push(20)

numStack.push(30)

 

let numElement = numStack.pop()  

Now that we utilize generics, our pop function returns a String alternate of any. This includes more type safety to our code and it eliminates unnecessary casting.

Value vs Reference Types

If you are working with swift in the early days, you may have listen about the Standard Library’s general use of value types. If you’re surprising what they are, now is a good time to find out, as the language is maturing and it doesn’t look like value types are going away anytime soon. To know value types, you require knowing reference types. Let’s take a stare at an example for Objective C:

NSString *myString = @"Hello, world!";

NSString *myOtherString = myString;

myString = @"Guess what? We have a problem.";

NSLog(myOtherString);

This is a major example of the danger of reference types. You observe when we set myOtherString to myString, the compiler didn’t copy the value of myStringand provide one copy to myOtherString. Instead, the compiler told myOtherString to reference myString. When myString changed, so did myOtherString. This kind of referencing can basis more bugs if developers do not use it carefully, so the designers of the Swift language select to use value types instead. Let’s stare at the same example in Swift:

var myString = "Hello, world!"

let myOtherString = myString

myString = "No problems here."

print(myOtherString)

No more bugs about strange reference semantics. This creates most code simplier to write and maintain for developers. structs are value types, and classes are reference types in swift. This information isn’t immediately useful in most day to day improvement work, but it’s useful to understand. It can also assist you make the choice when deciding between a class and a struct.


Posted

in

by

Comments

Leave a Reply

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