top of page
Writer's pictureSzymon Wnuk

Swift Essentials Series: Structs and Classes

Updated: Oct 1

In this series, we will cover fundamental components of the Swift programming language:


  1. Data Structures: Structs: Learn about value types and their usage in Swift. ✅ Classes: Understand reference types and how they differ from structs. ✅ Enumerations (Enums): Explore how to define and use enums for better code organization and readability.

  2. Protocols: Discover the power of protocols to define blueprints for methods, properties, and other requirements.

  3. Generics: Get to know how generics allow you to write flexible and reusable functions and types.

  4. Functions and Closures:

Functions: Delve into the details of defining, calling, and using functions.

Closures: Understand what closures are, how to use them, and their importance in Swift.


By the end of the whole series, you'll have a solid understanding of these Swift fundamentals and you will be able to write more efficient, readable, and maintainable code. Stay tuned as we dive into each topic with easy-to-understand examples and practical applications!





 

Today, we're going to learn about two important building blocks in Swift: Classes and Structs. Don't worry, we'll make it super easy to understand by using examples from something you're very familiar with—school! 🏫 Let's start then!



📚 Understanding Classes

Imagine a school with one classroom for each grade: kindergarten, first grade, second grade, and so on. Each classroom is unique but shares common features like having one teacher and a group of students. In Swift, we can use a class to represent each of these classrooms because classes can have shared properties and behaviors.


Classroom properties:

  • Teacher: Represented by a String (his name)

  • Students: Represented by a list of String (the name of each student)

Here’s how you might write a class in Swift:


class Classroom {
    var teacher: String
    var students: [String]
    
    init(teacher: String, students: [String]) {
        self.teacher = teacher
        self.students = students
    }
}

In this example, the Classroom class has two properties: teacher, and students.

Now that we have a class defined, let's create instances of the Classroom class. An instance is a specific object created from the class blueprint.


let kinderGarden = Classroom(teacher: "Smith", students: ["Bob, Taylor, Charlie"])
let firstGrade = Classroom(teacher: "Morrisey", students: ["Patrick, Susan, Kate"])

📚 Understanding Structures

Structures a have a similar definition syntax to classes. You can define a structure with the struct keyword.

Let's create a struct with the same properties as Classroom.

struct ClassroomStruct {
	var teacher: String
	var students: [String]
}

Instances:

let kinderGardenStruct = ClassroomStruct(teacher: "Smith", students: ["Bob", "Taylor", "Charlie"])
let firstGradeStruct = ClassroomStruct(teacher: "Morrisey", students: ["Patrick", "Susan", "Kate"])

Both of them look really similar but there are some differences.



📚 Key Differences Between Class and Struct


  • Value Type vs. Reference Type: ✅ Structs are value types. When you assign an instance of a struct to a new variable or pass it to a function, you're working with a copy of the data. ✅ Classes are reference types. When you assign an instance of a class to a new variable or pass it to a function, you're working with a reference to the same instance.


  • Mutability: ✅ Structs are immutable by default. If you want to modify the properties of a struct, you need to mark the instance as mutating. ✅ Classes are mutable by default. You can change the properties of a class instance directly.


  • Inheritance: ✅ Structs do not support inheritance. Each struct is a standalone type. You can extend protocols with a struct to avoid code repetition but we will see this later 😉 ✅ Classes support inheritance, meaning you can create a new class based on an existing class and inherit its properties and methods.


  • Memory Management: ✅ Structs are simpler in terms of memory management since they are value types and do not involve reference counting. ✅ Classes use reference counting (ARC) to manage memory, which can lead to reference cycles if not handled properly.


📚 Reference Type vs. Value Type

Let's illustrate the value type and reference type behavior with our school examples.


Class Example (Reference Type):

let kinderGardenClassCopy = kinderGarden
kinderGardenClassCopy.teacher = "Johnson"

print(kinderGarden.teacher)         // Output: Johnson
print(kinderGardenClassCopy.teacher) // Output: Johnson

Changing the teacher property of kinderGardenClassCopy also changes kinderGarden because classes are reference types and kinderGardenClassCopy is a reference to the same instance and not a new standalone object.

var kinderGardenStructCopy = kinderGardenStruct
kinderGardenStructCopy.teacher = "Johnson"

print(kinderGardenStruct.teacher)       // Output: Smith
print(kinderGardenStructCopy.teacher)   // Output: Johnson

In this example, changing the teacher property of kinderGardenStructCopy does not affect kinderGardenStruct because structs are value types and kinderGardenStructCopy is a copy.



Conclusion

Structures and classes are great choices for storing data and modeling behavior in your apps, but their similarities can make it difficult to choose one over the other.

Consider the following recommendations to help choose which option makes sense when adding a new data type to your app:

  • Use structures by default.

  • Use structures along with protocols to adopt behavior by sharing common attributes and function prototypes.

  • Use structs for data that doesn’t need to be shared or needs immutability. This makes them ideal for storing data fetched or sent to an API or to manage small scale data sets.

  • Use classes when you need Objective-C interoperability.

  • Use classes when you need to control the identity of the data you’re modeling.

  • Use classes for more complex objects that need to share and mutate state. When working with ObservableObject, you will mainly interact with classes, although the @Observable macro in iOS 17 allows for observing changes in structs.

Understanding the differences between structs and classes is crucial for effective Swift programming. You can keep this article at hand when starting a project to be sure to follow the guidelines introduced here. Next time we will dive into enums and how to get the best of them in your Swift code!


Thank you for reading and happy coding!



Comments


bottom of page