top of page

Chapter 5: Intermediate Swift!

  • Writer: arda doğantemur
    arda doğantemur
  • May 5, 2023
  • 3 min read

Updated: May 6, 2023



Generics

Generics are a powerful feature of Swift that allow us to write reusable code. With generics, we can write functions, types, and protocols that can work with a variety of types, without having to write separate code for each type.

Here's an example of a generic function that swaps two values of any type:

func swap<T>(_ a: inout T, _ b: inout T) {
    let temp = a
    a = b
    b = temp
}

var x = 10
var y = 20
swap(&x, &y) // x is now 20, y is now 10
var a = "hello"
var b = "world"
swap(&a, &b) // a is now "world", b is now "hello"

In this example, we define a generic function swap that takes two arguments of type T, and uses the inout keyword to indicate that they can be modified in place. The <T> syntax before the function name indicates that T is a type parameter.


Optionals

Optionals are a feature of Swift that allow us to represent the absence of a value. An optional is a type that can either contain a value of a specific type, or be nil.

Here's an example of how to declare an optional variable:

var optionalString: String? = "hello"

The ? after the type name indicates that optionalString is an optional that can either contain a String value, or be nil.

We can use optional binding to safely unwrap an optional value, like this:

if let unwrappedString = optionalString {
    print(unwrappedString)
} else {
    print("optionalString is nil")
}

In this example, we use the if let syntax to unwrap optionalString. If it contains a value, we bind it to the constant unwrappedString and print it. If it is nil, we print a message indicating that it is nil.


Enumerations

Enumerations, or enums for short, are a way of defining a group of related values in Swift. Enums can have associated values, which allows them to represent more complex data types.

Here's an example of how to define an enum:

enum CompassPoint {
    case north
    case south
    case east
    case west
}

var direction = CompassPoint.north
direction = .east

In this example, we define an enum called CompassPoint that has four cases: north, south, east, and west. We can assign one of these values to a variable of type CompassPoint, and change it later by using the shorthand .east notation.


Type casting

Type casting is the process of checking the type of an instance at runtime, and converting it to another type if needed. In Swift, we can use the is and as operators for type casting.

Here's an example of how to use type casting to check the type of an instance:

class Animal {
    func makeSound() {
        print("...")
    }
}

class Dog: Animal {
    override func makeSound() {
        print("woof!")
    }
}

let animal: Animal = Dog()
if animal is Dog {
    let dog = animal as! Dog
    dog.makeSound() // prints "woof!"
}

In this example, we define a class hierarchy with a base class Animal and a subclass Dog. We create an instance of Dog and assign it to a variable of type Animal. We then use the is operator to check if the instance is of type Dog, and if it is, we use the as operator to cast it to type Dog and call the makeSound() method on it.


Memory management

Memory management is the process of allocating and deallocating memory for our app's objects. In Swift, memory management is handled automatically using a feature called Automatic Reference Counting (ARC).

ARC keeps track of how many references there are to an object, and deallocates the object when there are no more references to it. This means that we don't have to worry about manually allocating or deallocating memory.

Here's an example of how ARC works:


class Person {     
    var name: String
    init(name: String) {         
        self.name = name     
    }     
    deinit {         
        print("\(name) has been deallocated")     
    } 
}  
var person1: Person? =Person(name: "Alice") 
var person2: Person? = person1 
var person3: Person? = person1 
person1 =nil 
person2 =nil 
person3 =nil

In this example, we define a class Person with a name property and a deinit method that prints a message when the object is deallocated. We create three variables that reference the same instance of Person. When we set person1, person2, and person3 to nil, ARC deallocates the Person instance and prints a message.


Opmerkingen


© 2020 by Arda Doğantemur.

bottom of page