Swift

Classes and Structs

When planning out a build of any kind, its important to understand the elements on which the structure will be built on. This helps identify different components, how they work according to the blue print, and what their purpose is when it comes to the build. In regards to building an iOS app, these elements consist of classes and structs. 

Classes and structs are the basing building blocks of an iOS app. They provide the ability of storing data and modeling behavior within the app. In a more overall sense, they help create objects that fill a certain role within the app, like actors in a play and the app is the stage on which they perform those roles and responsibilities. Or to go back to the construction metaphor, they are like rooms added to the blueprint of a house design where each room has a sense of purpose to the design: storing certain pieces of household items (data) and contribute to the flow of movement within the house and what their purpose of being there is intended for (behavior).

Now you might be saying “Great….but why have more than one thing when they both intend to do the same thing or have the same purpose?”. Well I’m glad you asked. This is the reason why I’m writing about this topic, so we can explore the similarities but all the differences each type can provide together.

Structs

Structs are known as value types. 

    • Value types are types whose values are copied when assigned to an object or passed into a function.
    • Value types keep a unique copy of its data.

To put it simply, let’s say you have the following:

  1. Here we’re declaring a new struct. To create a struct the syntax goes as, struct StructName. For this example we’re creating a struct called Home that contains 2 properties of type Int: bedrooms and bathrooms.
  2. Let’s create a new instance of Home called house1 that will have 3 bedrooms and 2 bathrooms.
  3. Now lets create a new variable instance of Home, house2, by setting it equal to house1.
  4. To properly show how the value type works, we’ll update house1’s property values to 5 bedrooms and 12 bathrooms, respectively. (Why 12 you may ask? Well that’s the mystery!)
  5. Finally we’ll print out our results. Here, you’ll notice that house1 and house2 contain two different values.

In the above example, you will note that, when we passed the initial value of house1 as the value for house2, they were the same. When we set the house1 values as the values for house2, the values of house1 were copied over to house2. But when we updated the values for house1 to 5 bedrooms and 12 bathrooms, the values for house2 remained the original 3 bedrooms and 2 bathrooms. This is because house2 retained a unique copy of house1’s original values and was not pointing to the same memory location so it was not updated with the newer values when house1 was updated. Pointing to the same memory location, and thereby both properties containing the same values, is a sign of reference type which we’ll get into a bit with classes.

Structs can have the following:

    • Properties – Objects that store values.
    • Methods – Provide functionality
    • Subscripts – Enable providing access to a structs values using the subscript syntax
    • Initializers – Used to set up initial state.
    • Extensions – Can be extended to expand functionality.

Classes

Classes are known as reference types.

    • Reference types contain a reference to the same existing instance that was used.
    • When two instances point to the same memory location, they are pulling the value(s) that are stored at that location.

Let’s go back to the blackboard to see an example of this in action:

    1. Create a new class called Apartment. The syntax to create a new class is class ClassName. Like the example in the Structs section, we’ll add two Int properties, bedrooms and bathrooms.
    2. Here we’ll initiate our first Apartment object, apt1, with 3 bedrooms and 2 bathrooms.
    3. Now we’ll create a new Apartment object, apt2, setting it equal to apt1.
    4. To better show how reference types operate, we’ll update apt1’s values to 5 bedrooms and 12 bathrooms(again…mystery).
    5. Finally, let’s print the results of both objects. Notice how they both contain the same values.

You can see in the results from the example that both apt1 and apt2 contain the same exact values. This is because, as discussed earlier, a class object is a reference type. When we set the value for  apt2 to the value of apt1, we are pointing apt2 to retrieve the values stored at the memory address where apt1 has its values stored. Tying it to the name, we are referencing the location where the code should retrieve the intended values. This means that whenever an update is made to that specific address, every instance that references that address will be update with the new values, as seen in the example above.

Classes can have the following:

    • Properties – Objects that store values.
    • Methods – Provide functionality
    • Subscripts – Enable providing access to a class values using the subscript syntax
    • Initializers – Used to set up initial state.
    • Extensions – Can be extended to expand functionality.

Now what are the differences?

Classes have additional capabilities:

    • Inheritance- where one class can inherit characteristics of another.
    • Type casting- enabling to check and interpret the type of class at runtime.
    • Deinitializers- the ability to free up any resources originally assigned.
    • Reference counting- allowing more than reference to a class instance.
    • Ability to work better with Objective-C code

Structs get inits for free, meaning if you don’t specifically declare an init within the struct, Swift will provide it for free. 

The above example shows when we don’t provide an initializer for a class, the compiler doesn’t know what to do and complains, where as the struct has no problems when an initializer is not provided in it.

Unlike class methods, struct methods cannot update a struct’s properties without applying the mutating keyword to the method signature. 

While structs can’t inherit from other structs directly, like classes can from other classes, they can conform to a way of inheritance by conforming to protocols. Protocols enable for structs, protocols, and enumerations to participate in a form of inheritance.

 

Conclusion

According to Apple’s recommendation, structs should be the way to go when developing your app. Structs reduce complexity within your code base, by way of being a value type that lives within a stack and each thread has its own stack. This prevents the struct values from being modified outside of the thread it lives on during a certain lifecycle, thereby avoiding race conditions, deadlocks, locks and any thread related synchronization complexity. “Using structures makes it easier to reason about a portion of your code without needing to consider the whole state of your app.” – Apple

In the event you need to keep track of identity for your models, require inheritance if better suited for your architecture, or need to tap into Objective-C to use its capabilities, classes are the way to go.

I hope you found this first blog post educational and insightful. I learned more about structs and classes from researching this topic than I thought I knew originally. If I find more information that could help deepen our understanding of this topics, I’ll make sure to update in the future.

But for now, thanks, and bon voyage!

Resources