30 Days of SwiftUI - Day 7: Cracking the Code with Swift Classes

๐Ÿ—️ Crafting Custom Types: Creating Your Own Classes

Classes are powerful building blocks in Swift that allow you to create custom data types with properties and methods.

Example:

class Car {
    var brand: String
    var year: Int

    init(brand: String, year: Int) {
        self.brand = brand
        self.year = year
    }
}

let myCar = Car(brand: "Tesla", year: 2024)
print(myCar.brand) // Output: Tesla

๐Ÿ”Ž Classes vs Structs: What's the Big Deal?

FeatureStructsClasses
Value Type                Yes    No (Reference Type)
Inheritance                        No                Yes
Deinitializer                No                Yes
Memberwise Initializer    Yes (Auto-generated)                 No

Use structs for simple data models and classes when you need shared references or inheritance.


๐Ÿคท‍♂️ Why Don’t Classes Have a Memberwise Initializer?

Unlike structs, Swift doesn’t automatically create a memberwise initializer for classes because they are designed for more complex configurations.

Example:

class Laptop {
    var brand: String
    var model: String
    
    init(brand: String, model: String) {
        self.brand = brand
        self.model = model
    }
}

๐Ÿ‘จ‍๐Ÿ‘ฉ‍๐Ÿ‘ฆ Unlocking Power: Understanding Inheritance

Inheritance lets one class inherit properties and methods from another, promoting code reuse.

Example:

class Vehicle {
    var speed = 0

    func accelerate() {
        speed += 10
    }
}

class Car: Vehicle {
    func honk() {
        print("Beep Beep!")
    }
}

let car = Car()
car.accelerate()
print(car.speed) // Output: 10
car.honk()        // Output: Beep Beep!

๐Ÿ”„ When Should You Override a Method?

Use override to customize inherited behavior in subclasses.

Example:

class Animal {
    func speak() {
        print("Animal makes a sound")
    }
}

class Dog: Animal {
    override func speak() {
        print("Woof Woof!")
    }
}

let dog = Dog()
dog.speak() // Output: Woof Woof!

๐Ÿšซ When to Declare a Class as final

Marking a class as final prevents it from being subclassed, ensuring its behavior remains intact.

Example:

final class Account {
    var balance = 1000
}

// Error: Cannot inherit from final class 'Account'
// class SavingsAccount: Account {}

๐Ÿ”„ Customizing Initialization: Adding Initializers for Classes

Just like structs, classes can have custom initializers to manage setup logic.

Example:

class Person {
    var name: String
    var age: Int

    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}

๐Ÿ“‹ Copying Classes: Reference vs Value Types

Classes in Swift are reference types, meaning that copying a class instance creates a new reference to the same data.

Example:

class User {
    var name: String = "Gati"
}

let user1 = User()
let user2 = user1
user2.name = "Shah"
print(user1.name) // Output: Shah

Both user1 and user2 point to the same instance in memory.


❓ Why Do Class Copies Share Data?

Since classes are reference types, they point to the same memory address rather than creating a new copy.


๐Ÿงน Cleaning Up: Deinitializers in Swift

Classes can have a deinit method to handle cleanup when the object is being destroyed.

Example:

class FileHandler {
    init() {
        print("File opened")
    }

    deinit {
        print("File closed")
    }
}

var handler: FileHandler? = FileHandler() // Output: File opened
handler = nil                             // Output: File closed

๐Ÿ”ฅ Why Do Classes Have Deinitializers (and Structs Don’t)?

Since structs are value types, they get destroyed automatically when they go out of scope. Classes need deinit to manually release resources when an instance is no longer needed.


⚙️ Managing Variables Inside Classes

Classes allow flexible handling of variables, even in constant class instances.

Example:

class Counter {
    var value = 0
}

let counter = Counter()
counter.value = 10  // This works, even though `counter` is a constant

๐Ÿค” Why Can Class Variables Change in Constant Instances?

Since class instances are references, marking the instance as constant only prevents changing the reference itself, not the properties inside it.


✅ Checkpoint Challenge: Test Your Skills!

Question: Create a class Rectangle with width and height properties, a method that calculates its area, and a deinitializer that prints a goodbye message.

Answer:

class Rectangle {
    var width: Double
    var height: Double

    init(width: Double, height: Double) {
        self.width = width
        self.height = height
    }

    func area() -> Double {
        return width * height
    }

    deinit {
        print("Rectangle instance is being removed.")
    }
}

var rect: Rectangle? = Rectangle(width: 5, height: 10)
print(rect?.area() ?? 0) // Output: 50
rect = nil                // Output: Rectangle instance is being removed.

๐Ÿ“Œ Summary: Mastering Classes in Swift

✅ Classes enable complex data modeling with reference types. ✅ Inheritance simplifies code reuse and customization. ✅ Use final to prevent subclassing when necessary. ✅ Remember, class instances share data, while structs create unique copies. ✅ Deinitializers ensure proper cleanup of resources.


Follow me on Linkedin: igatitech ๐Ÿš€๐Ÿš€๐Ÿš€

Comments

Popular posts from this blog

30 Days of SwiftUI — Day 1: Getting Started with SwiftUI

30 Days of SwiftUI Learning Journey: From Zero to Hero!

30 Days of SwiftUI - Day 11: Building Interactive SwiftUI Apps