Blog / August 2, 2023 / 2 mins read / By Mahi Garg

class vs struct: Swift

In the realm of Swift programming, the choice between using classes or structs can significantly impact your code’s design, efficiency, and behavior. In this blog, we’ll embark on a journey through class and struct differences, focusing on scenarios where classes outshine structs. By exploring practical examples, we’ll illuminate the unique capabilities that classes bring to the table.

Understanding the Basics

Before diving into the specifics, let’s recap the fundamental contrasts between classes and structs:

Classes:

  • Reference types
  • Support inheritance
  • Have a deinit method for custom deallocation
  • Allow for shared instances with reference semantics

Structs:

  • Value types
  • No inheritance but support protocol conformance
  • No deinit since they’re automatically deallocated
  • Create distinct copies for each instance

Harnessing Class Power

Example: Hierarchical Relationships

When your application demands a hierarchy of related entities with shared properties and behaviors, classes excel. Consider modeling a vehicle fleet:

class Vehicle {
    var brand: String

    init(brand: String) {
        self.brand = brand
    }

    func startEngine() {
        print("Engine started for \(brand)")
    }
}

class Car: Vehicle {
    var passengers: Int

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

    override func startEngine() {
        super.startEngine()
        print("Car is ready to roll!")
    }
}

Here, using classes enables you to establish a hierarchy by subclassing Vehicle with a specialized class Car.

Example: Shared Instances

When dealing with complex data models or entities that require shared state, classes shine. Let’s consider managing a shopping cart:

class ShoppingCart {
    static let shared = ShoppingCart()
    var items: [String] = []

    private init() {}
}

let cart1 = ShoppingCart.shared
let cart2 = ShoppingCart.shared

cart1.items.append("Item A")
print(cart2.items)  // Output: ["Item A"]

In this case, the shared instance of ShoppingCart serves as a centralized storage for shopping items, thanks to classes’ reference semantics.

Example: Custom Deinitialization

If you need to perform cleanup operations before an instance is deallocated, classes offer the deinit method. Consider a database connection:

class DatabaseConnection {
    init() {
        print("Database connection established")
    }

    deinit {
        print("Database connection closed")
    }
}

var connection: DatabaseConnection? = DatabaseConnection()
connection = nil  // Output: Database connection closed

Here, the deinit method ensures proper resource release, showcasing classes’ capacity for custom cleanup.

Conclusion

While structs have their merits in scenarios like immutability and simple data structures, classes provide indispensable features like inheritance, reference semantics, and custom deinitialization. Through real-world examples, we’ve uncovered how classes outperform structs in handling hierarchical relationships, shared instances, and cleanup tasks. By recognizing these distinctions, you’ll adeptly wield both classes and structs to create efficient, organized, and powerful Swift codebases.

Comments